New upstream version 3.7.0
authorÉtienne Mollier <emollier@debian.org>
Thu, 18 Dec 2025 21:30:06 +0000 (22:30 +0100)
committerÉtienne Mollier <emollier@debian.org>
Thu, 18 Dec 2025 21:30:06 +0000 (22:30 +0100)
696 files changed:
.github/workflows/cmake-win.yml
.gitignore
ANNOUNCE
CMake/3rdparty.cmake
CMake/CTest/CTestCustomAndroid.cmake.in
CMake/CTest/dcmtkCTestRunAndroid.cmake.in
CMake/DCMTKConfig.cmake.in
CMake/GenerateDCMTKConfigure.cmake
CMake/dcmtkMacros.cmake
CMake/dcmtkPrepare.cmake
CMake/dcmtkUseAndroidSDK.cmake
CMake/osconfig.h.in
CMakeLists.txt
COPYRIGHT
CREDITS
INSTALL
Makefile
VERSION
config/aclocal.m4
config/configure
config/configure.in
config/confmod
config/docs/macros.txt
config/include/dcmtk/config/osconfig.h.in
config/math.cc
config/modules
dcmapps/apps/CMakeLists.txt
dcmapps/docs/dcm2img.man
dcmapps/include/dcmtk/dcmapps/dcm2img.h
dcmdata/apps/CMakeLists.txt
dcmdata/apps/Makefile.dep
dcmdata/apps/Makefile.in
dcmdata/apps/cda2dcm.cc
dcmdata/apps/dcm2cda.cc
dcmdata/apps/dcm2json.cc
dcmdata/apps/dcm2pdf.cc
dcmdata/apps/dcm2xml.cc
dcmdata/apps/dcmdecap.cc [new file with mode: 0644]
dcmdata/apps/dcmencap.cc [new file with mode: 0644]
dcmdata/apps/dump2dcm.cc
dcmdata/apps/img2dcm.cc
dcmdata/apps/json2dcm.cc [new file with mode: 0644]
dcmdata/apps/mdfdsman.cc
dcmdata/apps/pdf2dcm.cc
dcmdata/apps/stl2dcm.cc
dcmdata/data/dicom.dic
dcmdata/docs/cda2dcm.man
dcmdata/docs/dcm2cda.man
dcmdata/docs/dcm2json.man
dcmdata/docs/dcm2pdf.man
dcmdata/docs/dcm2xml.man
dcmdata/docs/dcmconv.man
dcmdata/docs/dcmcrle.man
dcmdata/docs/dcmdata.dox
dcmdata/docs/dcmdecap.man [new file with mode: 0644]
dcmdata/docs/dcmdrle.man
dcmdata/docs/dcmdump.man
dcmdata/docs/dcmencap.man [new file with mode: 0644]
dcmdata/docs/dcmftest.man
dcmdata/docs/dcmgpdir.man
dcmdata/docs/dcmodify.man
dcmdata/docs/dump2dcm.man
dcmdata/docs/img2dcm.man
dcmdata/docs/json2dcm.man [new file with mode: 0644]
dcmdata/docs/pdf2dcm.man
dcmdata/docs/stl2dcm.man
dcmdata/docs/xml2dcm.man
dcmdata/include/dcmtk/dcmdata/dcbytstr.h
dcmdata/include/dcmtk/dcmdata/dccodec.h
dcmdata/include/dcmtk/dcmdata/dcdatset.h
dcmdata/include/dcmtk/dcmdata/dcddirif.h
dcmdata/include/dcmtk/dcmdata/dcdeftag.h
dcmdata/include/dcmtk/dcmdata/dcdirrec.h
dcmdata/include/dcmtk/dcmdata/dcdocdec.h [new file with mode: 0644]
dcmdata/include/dcmtk/dcmdata/dcelem.h
dcmdata/include/dcmtk/dcmdata/dcencdoc.h
dcmdata/include/dcmtk/dcmdata/dcerror.h
dcmdata/include/dcmtk/dcmdata/dcfilefo.h
dcmdata/include/dcmtk/dcmdata/dcitem.h
dcmdata/include/dcmtk/dcmdata/dcjson.h
dcmdata/include/dcmtk/dcmdata/dcjsonrd.h [new file with mode: 0644]
dcmdata/include/dcmtk/dcmdata/dclist.h
dcmdata/include/dcmtk/dcmdata/dcmetinf.h
dcmdata/include/dcmtk/dcmdata/dcmxml/xml2dcm.h
dcmdata/include/dcmtk/dcmdata/dcpixel.h
dcmdata/include/dcmtk/dcmdata/dcpixseq.h
dcmdata/include/dcmtk/dcmdata/dcrleccd.h
dcmdata/include/dcmtk/dcmdata/dcrlecce.h
dcmdata/include/dcmtk/dcmdata/dcspchrs.h
dcmdata/include/dcmtk/dcmdata/dctypes.h
dcmdata/include/dcmtk/dcmdata/dcuid.h
dcmdata/include/dcmtk/dcmdata/dcvrae.h
dcmdata/include/dcmtk/dcmdata/dcvrobow.h
dcmdata/include/dcmtk/dcmdata/dcxfer.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2d.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2djpgs.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2doutpl.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2dplnsc.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2dplop.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2dplsc.h
dcmdata/include/dcmtk/dcmdata/libi2d/i2dplvlp.h
dcmdata/libdcxml/Makefile.dep
dcmdata/libdcxml/xml2dcm.cc
dcmdata/libi2d/Makefile.dep
dcmdata/libi2d/i2d.cc
dcmdata/libi2d/i2djpgs.cc
dcmdata/libi2d/i2dplnsc.cc
dcmdata/libi2d/i2dplop.cc
dcmdata/libi2d/i2dplsc.cc
dcmdata/libi2d/i2dplvlp.cc
dcmdata/libsrc/CMakeLists.txt
dcmdata/libsrc/Makefile.dep
dcmdata/libsrc/Makefile.in
dcmdata/libsrc/cmdlnarg.cc
dcmdata/libsrc/dcbytstr.cc
dcmdata/libsrc/dcchrstr.cc
dcmdata/libsrc/dccodec.cc
dcmdata/libsrc/dcdatset.cc
dcmdata/libsrc/dcddirif.cc
dcmdata/libsrc/dcdict.cc
dcmdata/libsrc/dcdictbi.cc
dcmdata/libsrc/dcdirrec.cc
dcmdata/libsrc/dcdocdec.cc [new file with mode: 0644]
dcmdata/libsrc/dcelem.cc
dcmdata/libsrc/dcencdoc.cc
dcmdata/libsrc/dcerror.cc
dcmdata/libsrc/dcfilefo.cc
dcmdata/libsrc/dcistrmf.cc
dcmdata/libsrc/dcistrms.cc
dcmdata/libsrc/dcistrmz.cc
dcmdata/libsrc/dcitem.cc
dcmdata/libsrc/dcjson.cc
dcmdata/libsrc/dcjsonrd.cc [new file with mode: 0644]
dcmdata/libsrc/dclist.cc
dcmdata/libsrc/dcmetinf.cc
dcmdata/libsrc/dcostrmf.cc
dcmdata/libsrc/dcostrms.cc
dcmdata/libsrc/dcpixel.cc
dcmdata/libsrc/dcpixseq.cc
dcmdata/libsrc/dcrleccd.cc
dcmdata/libsrc/dcrlecce.cc
dcmdata/libsrc/dcspchrs.cc
dcmdata/libsrc/dcuid.cc
dcmdata/libsrc/dcvrds.cc
dcmdata/libsrc/dcvrfd.cc
dcmdata/libsrc/dcvrfl.cc
dcmdata/libsrc/dcvris.cc
dcmdata/libsrc/dcvrobow.cc
dcmdata/libsrc/dcvrod.cc
dcmdata/libsrc/dcvrof.cc
dcmdata/libsrc/dcvrol.cc
dcmdata/libsrc/dcvrov.cc
dcmdata/libsrc/dcvrpobw.cc
dcmdata/libsrc/dcvrsv.cc
dcmdata/libsrc/dcvruv.cc
dcmdata/libsrc/dcxfer.cc
dcmdata/libsrc/vrscanl.c
dcmdata/libsrc/vrscanl.l
dcmdata/tests/CMakeLists.txt
dcmdata/tests/Makefile.dep
dcmdata/tests/Makefile.in
dcmdata/tests/tchval.cc
dcmdata/tests/tests.cc
dcmdata/tests/tfilter.cc
dcmdata/tests/tfrmsiz.cc [new file with mode: 0644]
dcmdata/tests/tsequen.cc
dcmdata/tests/tvrdatim.cc
dcmect/include/dcmtk/dcmect/enhanced_ct.h
dcmect/libsrc/Makefile.dep
dcmect/libsrc/enhanced_ct.cc
dcmect/tests/CMakeLists.txt
dcmect/tests/Makefile.dep
dcmect/tests/t_huge_concat.cc
dcmect/tests/t_overflow.cc
dcmfg/include/dcmtk/dcmfg/concatenationcreator.h
dcmfg/include/dcmtk/dcmfg/concatenationloader.h
dcmfg/include/dcmtk/dcmfg/fg.h
dcmfg/include/dcmtk/dcmfg/fgderimg.h
dcmfg/include/dcmtk/dcmfg/fginterface.h
dcmfg/include/dcmtk/dcmfg/fgseg.h
dcmfg/include/dcmtk/dcmfg/fgtypes.h
dcmfg/include/dcmtk/dcmfg/framesorter.h [new file with mode: 0644]
dcmfg/libsrc/Makefile.dep
dcmfg/libsrc/concatenationcreator.cc
dcmfg/libsrc/concatenationloader.cc
dcmfg/libsrc/fg.cc
dcmfg/libsrc/fgderimg.cc
dcmfg/libsrc/fginterface.cc
dcmfg/libsrc/fgseg.cc
dcmfg/libsrc/fgtypes.cc
dcmfg/tests/CMakeLists.txt
dcmfg/tests/Makefile.dep
dcmfg/tests/t_concatenation_loader.cc
dcmfg/tests/t_fg_base.cc
dcmimage/docs/dcm2pnm.man
dcmimage/docs/dcmicmp.man
dcmimage/docs/dcmquant.man
dcmimage/docs/dcmscale.man
dcmimage/include/dcmtk/dcmimage/dicomot.h
dcmimage/include/dcmtk/dcmimage/dicopxt.h
dcmimage/include/dcmtk/dcmimage/diqtpbox.h
dcmimage/include/dcmtk/dcmimage/diybrpxt.h
dcmimage/libsrc/Makefile.dep
dcmimage/libsrc/dipitiff.cc
dcmimage/libsrc/diqtctab.cc
dcmimgle/docs/dcmdspfn.man
dcmimgle/docs/dcod2lum.man
dcmimgle/docs/dconvlum.man
dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
dcmimgle/include/dcmtk/dcmimgle/diluptab.h
dcmimgle/include/dcmtk/dcmimgle/dimocpt.h
dcmimgle/include/dcmtk/dcmimgle/dimoflt.h
dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
dcmimgle/include/dcmtk/dcmimgle/dimopxt.h
dcmimgle/include/dcmtk/dcmimgle/dimorot.h
dcmimgle/include/dcmtk/dcmimgle/dimosct.h
dcmimgle/include/dcmtk/dcmimgle/diutils.h
dcmimgle/libsrc/Makefile.dep
dcmimgle/libsrc/dcmimage.cc
dcmimgle/libsrc/dicielut.cc
dcmimgle/libsrc/didocu.cc
dcmimgle/libsrc/digsdlut.cc
dcmimgle/libsrc/diimage.cc
dcmimgle/libsrc/diluptab.cc
dcmimgle/libsrc/dimoimg.cc
dcmiod/include/dcmtk/dcmiod/iccexample.h [new file with mode: 0644]
dcmiod/include/dcmtk/dcmiod/iodimage.h
dcmiod/include/dcmtk/dcmiod/iodrules.h
dcmiod/include/dcmtk/dcmiod/iodtypes.h
dcmiod/include/dcmtk/dcmiod/iodutil.h
dcmiod/include/dcmtk/dcmiod/modbase.h
dcmiod/include/dcmtk/dcmiod/modequipment.h
dcmiod/include/dcmtk/dcmiod/modgeneralimage.h
dcmiod/include/dcmtk/dcmiod/modiccprofile.h [new file with mode: 0644]
dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h
dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h [new file with mode: 0644]
dcmiod/libsrc/CMakeLists.txt
dcmiod/libsrc/Makefile.dep
dcmiod/libsrc/Makefile.in
dcmiod/libsrc/iodmacro.cc
dcmiod/libsrc/iodrules.cc
dcmiod/libsrc/iodtypes.cc
dcmiod/libsrc/iodutil.cc
dcmiod/libsrc/modequipment.cc
dcmiod/libsrc/modhelp.cc
dcmiod/libsrc/modiccprofile.cc [new file with mode: 0644]
dcmiod/libsrc/modmultiframedimension.cc
dcmiod/libsrc/modpalettecolorlut.cc [new file with mode: 0644]
dcmiod/tests/CMakeLists.txt
dcmiod/tests/Makefile.dep
dcmiod/tests/Makefile.in
dcmiod/tests/tchecks.cc
dcmiod/tests/tests.cc
dcmiod/tests/ticcprofile.cc [new file with mode: 0644]
dcmiod/tests/tmacro.cc [new file with mode: 0644]
dcmiod/tests/tpalette.cc [new file with mode: 0644]
dcmjpeg/apps/dcmdjpeg.cc
dcmjpeg/docs/dcmcjpeg.man
dcmjpeg/docs/dcmdjpeg.man
dcmjpeg/docs/dcmj2pnm.man
dcmjpeg/docs/dcmmkdir.man
dcmjpeg/include/dcmtk/dcmjpeg/djcodecd.h
dcmjpeg/include/dcmtk/dcmjpeg/djcodece.h
dcmjpeg/include/dcmtk/dcmjpeg/djcparam.h
dcmjpeg/include/dcmtk/dcmjpeg/djdecode.h
dcmjpeg/libijg12/jconfig12.h
dcmjpeg/libijg12/jerror.c
dcmjpeg/libijg16/jconfig16.h
dcmjpeg/libijg16/jerror.c
dcmjpeg/libijg8/jconfig8.h
dcmjpeg/libijg8/jerror.c
dcmjpeg/libsrc/Makefile.dep
dcmjpeg/libsrc/djcodecd.cc
dcmjpeg/libsrc/djcodece.cc
dcmjpeg/libsrc/djcparam.cc
dcmjpeg/libsrc/djdecode.cc
dcmjpls/apps/CMakeLists.txt
dcmjpls/docs/dcmcjpls.man
dcmjpls/docs/dcmdjpls.man
dcmjpls/docs/dcml2pnm.man
dcmjpls/include/dcmtk/dcmjpls/djcodecd.h
dcmjpls/include/dcmtk/dcmjpls/djcodece.h
dcmjpls/libcharls/encodstr.h
dcmjpls/libcharls/lltraits.h
dcmjpls/libcharls/scan.h
dcmjpls/libcharls/streams.h
dcmjpls/libsrc/djcodecd.cc
dcmjpls/libsrc/djcodece.cc
dcmnet/apps/CMakeLists.txt
dcmnet/apps/Makefile.dep
dcmnet/apps/Makefile.in
dcmnet/apps/dcmrecv.cc
dcmnet/apps/echoscu.cc
dcmnet/apps/movescu.cc
dcmnet/apps/storescp.cc
dcmnet/docs/dcmrecv.man
dcmnet/docs/dcmsend.man
dcmnet/docs/echoscu.man
dcmnet/docs/findscu.man
dcmnet/docs/getscu.man
dcmnet/docs/movescu.man
dcmnet/docs/storescp.man
dcmnet/docs/storescu.man
dcmnet/docs/termscu.man
dcmnet/etc/storescp.cfg
dcmnet/etc/storescu.cfg
dcmnet/include/dcmtk/dcmnet/assoc.h
dcmnet/include/dcmtk/dcmnet/dcompat.h
dcmnet/include/dcmtk/dcmnet/dul.h
dcmnet/include/dcmtk/dcmnet/scp.h
dcmnet/include/dcmtk/dcmnet/scpcfg.h
dcmnet/include/dcmtk/dcmnet/scppool.h
dcmnet/include/dcmtk/dcmnet/scpthrd.h
dcmnet/include/dcmtk/dcmnet/scu.h
dcmnet/libsrc/assoc.cc
dcmnet/libsrc/dcmtrans.cc
dcmnet/libsrc/dcompat.cc
dcmnet/libsrc/dimcancl.cc
dcmnet/libsrc/dimcmd.cc
dcmnet/libsrc/dimdump.cc
dcmnet/libsrc/dimfind.cc
dcmnet/libsrc/dimget.cc
dcmnet/libsrc/dimmove.cc
dcmnet/libsrc/dimse.cc
dcmnet/libsrc/dimstore.cc
dcmnet/libsrc/diutil.cc
dcmnet/libsrc/dstorscp.cc
dcmnet/libsrc/dul.cc
dcmnet/libsrc/dulextra.cc
dcmnet/libsrc/dulfsm.cc
dcmnet/libsrc/scp.cc
dcmnet/libsrc/scpcfg.cc
dcmnet/libsrc/scppool.cc
dcmnet/libsrc/scpthrd.cc
dcmnet/libsrc/scu.cc
dcmnet/tests/tpool.cc
dcmpmap/include/dcmtk/dcmpmap/dpmparametricmapiod.h
dcmpmap/libsrc/Makefile.dep
dcmpmap/libsrc/dpmparametricmapiod.cc
dcmpstat/apps/CMakeLists.txt
dcmpstat/apps/Makefile.dep
dcmpstat/apps/dcmprscp.cc
dcmpstat/apps/dcmprscu.cc
dcmpstat/apps/dcmpschk.cc
dcmpstat/apps/dcmpsmk.cc
dcmpstat/apps/dcmpsrcv.cc
dcmpstat/apps/dcmpssnd.cc
dcmpstat/docs/dcmmkcrv.man
dcmpstat/docs/dcmmklut.man
dcmpstat/docs/dcmp2pgm.man
dcmpstat/docs/dcmprscp.man
dcmpstat/docs/dcmprscu.man
dcmpstat/docs/dcmpschk.man
dcmpstat/docs/dcmpsmk.man
dcmpstat/docs/dcmpsprt.man
dcmpstat/docs/dcmpsrcv.man
dcmpstat/docs/dcmpssnd.man
dcmpstat/etc/dcmpstat.cfg
dcmpstat/include/dcmtk/dcmpstat/dviface.h
dcmpstat/include/dcmtk/dcmpstat/dvpscf.h
dcmpstat/include/dcmtk/dcmpstat/dvpsri.h
dcmpstat/libsrc/Makefile.dep
dcmpstat/libsrc/dviface.cc
dcmpstat/libsrc/dvpscf.cc
dcmpstat/libsrc/dvpshlp.cc
dcmpstat/libsrc/dvpsmsg.cc
dcmpstat/libsrc/dvpsri.cc
dcmpstat/tests/CMakeLists.txt
dcmpstat/tests/msgserv.cc
dcmqrdb/apps/dcmqrscp.cc
dcmqrdb/docs/dcmqridx.man
dcmqrdb/docs/dcmqrscp.man
dcmqrdb/docs/dcmqrti.man
dcmqrdb/etc/dcmqrprf.cfg
dcmqrdb/include/dcmtk/dcmqrdb/dcmqrcbm.h
dcmqrdb/include/dcmtk/dcmqrdb/dcmqropt.h
dcmqrdb/libsrc/dcmqrcbg.cc
dcmqrdb/libsrc/dcmqrcbm.cc
dcmqrdb/libsrc/dcmqrcnf.cc
dcmqrdb/libsrc/dcmqrdbi.cc
dcmqrdb/libsrc/dcmqropt.cc
dcmqrdb/libsrc/dcmqrsrv.cc
dcmqrdb/libsrc/dcmqrtis.cc
dcmrt/apps/CMakeLists.txt
dcmrt/docs/drtdump.man
dcmrt/include/dcmtk/dcmrt/drttypes.h
dcmrt/libsrc/drtdose.cc
dcmrt/libsrc/drtimage.cc
dcmrt/libsrc/drtionpl.cc
dcmrt/libsrc/drtiontr.cc
dcmrt/libsrc/drtplan.cc
dcmrt/libsrc/drtstrct.cc
dcmrt/libsrc/drttreat.cc
dcmrt/tests/CMakeLists.txt
dcmseg/Makefile.in
dcmseg/include/dcmtk/dcmseg/overlaputil.h [new file with mode: 0644]
dcmseg/include/dcmtk/dcmseg/segdoc.h
dcmseg/include/dcmtk/dcmseg/segment.h
dcmseg/include/dcmtk/dcmseg/segtypes.h
dcmseg/include/dcmtk/dcmseg/segutils.h
dcmseg/libsrc/CMakeLists.txt
dcmseg/libsrc/Makefile.dep
dcmseg/libsrc/Makefile.in
dcmseg/libsrc/overlaputil.cc [new file with mode: 0644]
dcmseg/libsrc/segdoc.cc
dcmseg/libsrc/segment.cc
dcmseg/libsrc/segtypes.cc
dcmseg/libsrc/segutils.cc
dcmseg/tests/CMakeLists.txt
dcmseg/tests/Makefile.dep
dcmseg/tests/Makefile.in
dcmseg/tests/tbigdim.cc
dcmseg/tests/tconcat_binary.cc
dcmseg/tests/tests.cc
dcmseg/tests/tlabelmap.cc [new file with mode: 0644]
dcmseg/tests/tpacking.cc [new file with mode: 0644]
dcmseg/tests/troundtrip.cc
dcmseg/tests/tutils.cc
dcmsign/docs/dcmsign.man
dcmsr/apps/Makefile.dep
dcmsr/apps/dsr2html.cc
dcmsr/apps/dsrdump.cc
dcmsr/apps/xml2dsr.cc
dcmsr/data/dsr2xml.xsd
dcmsr/docs/dsr2html.man
dcmsr/docs/dsr2xml.man
dcmsr/docs/dsrdump.man
dcmsr/docs/xml2dsr.man
dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
dcmsr/include/dcmtk/dcmsr/cmr/tid1500.h
dcmsr/include/dcmtk/dcmsr/cmr/tid15def.h
dcmsr/include/dcmtk/dcmsr/cmr/tid1600.h
dcmsr/include/dcmtk/dcmsr/codes/dcm.h
dcmsr/include/dcmtk/dcmsr/codes/ncit.h
dcmsr/include/dcmtk/dcmsr/codes/umls.h
dcmsr/include/dcmtk/dcmsr/dsrcomvl.h
dcmsr/include/dcmtk/dcmsr/dsrctxgr.h
dcmsr/include/dcmtk/dcmsr/dsrdoc.h
dcmsr/include/dcmtk/dcmsr/dsrdoctn.h
dcmsr/include/dcmtk/dcmsr/dsrdoctr.h
dcmsr/include/dcmtk/dcmsr/dsrimgvl.h
dcmsr/include/dcmtk/dcmsr/dsrtypes.h
dcmsr/include/dcmtk/dcmsr/dsrwavvl.h
dcmsr/include/dcmtk/dcmsr/dsrxmlc.h
dcmsr/libcmr/cid100.cc
dcmsr/libcmr/cid10013.cc
dcmsr/libcmr/cid10033.cc
dcmsr/libcmr/cid11.cc
dcmsr/libcmr/cid218.cc
dcmsr/libcmr/cid244.cc
dcmsr/libcmr/cid247.cc
dcmsr/libcmr/cid29.cc
dcmsr/libcmr/cid4020.cc
dcmsr/libcmr/cid4021.cc
dcmsr/libcmr/cid4031.cc
dcmsr/libcmr/cid42.cc
dcmsr/libcmr/cid5000.cc
dcmsr/libcmr/cid5001.cc
dcmsr/libcmr/cid6147.cc
dcmsr/libcmr/cid7021.cc
dcmsr/libcmr/cid7181.cc
dcmsr/libcmr/cid7445.cc
dcmsr/libcmr/cid7452.cc
dcmsr/libcmr/cid7453.cc
dcmsr/libcmr/cid7464.cc
dcmsr/libcmr/cid7469.cc
dcmsr/libcmr/cid7551.cc
dcmsr/libsrc/Makefile.dep
dcmsr/libsrc/dsrctxgr.cc
dcmsr/libsrc/dsrdoc.cc
dcmsr/libsrc/dsrdoctn.cc
dcmsr/libsrc/dsrimgvl.cc
dcmsr/libsrc/dsrnumvl.cc
dcmsr/libsrc/dsrtypes.cc
dcmsr/libsrc/dsrxmld.cc
dcmsr/tests/CMakeLists.txt
dcmsr/tests/Makefile.dep
dcmsr/tests/Makefile.in
dcmsr/tests/tests.cc
dcmsr/tests/tsrcmr.cc
dcmsr/tests/tsrdoc.cc
dcmsr/tests/tsrimgvl.cc [new file with mode: 0644]
dcmtls/include/dcmtk/dcmtls/tlsscu.h
dcmtls/libsrc/tlsciphr.cc
dcmtls/libsrc/tlsfmacr.h
dcmtls/libsrc/tlsscu.cc
dcmtls/libsrc/tlstrans.cc
dcmtls/tests/CMakeLists.txt
dcmtls/tests/tscuscptls.cc
dcmtract/CMakeLists.txt
dcmtract/include/dcmtk/dcmtract/trctrackset.h
dcmtract/include/dcmtk/dcmtract/trctypes.h
dcmtract/libsrc/Makefile.dep
dcmtract/libsrc/trcmodtractresults.cc
dcmtract/libsrc/trctrackset.cc
dcmtract/libsrc/trctractographyresults.cc
dcmtract/libsrc/trctypes.cc
dcmtract/tests/CMakeLists.txt [new file with mode: 0644]
dcmtract/tests/Makefile.dep
dcmtract/tests/Makefile.in
dcmtract/tests/tcreate.cc [new file with mode: 0644]
dcmtract/tests/tests.cc [new file with mode: 0644]
dcmwlm/apps/CMakeLists.txt
dcmwlm/apps/wlcefs.cc
dcmwlm/docs/wlmscpfs.man
dcmwlm/include/dcmtk/dcmwlm/wlds.h
dcmwlm/libsrc/wlds.cc
dcmwlm/libsrc/wldsfs.cc
dcmwlm/tests/CMakeLists.txt
docs/ANNOUNCE.369 [new file with mode: 0644]
docs/CHANGES.370 [new file with mode: 0644]
doxygen/manpages/man1/cda2dcm.1
doxygen/manpages/man1/dcm2cda.1
doxygen/manpages/man1/dcm2img.1
doxygen/manpages/man1/dcm2json.1
doxygen/manpages/man1/dcm2pdf.1
doxygen/manpages/man1/dcm2pnm.1
doxygen/manpages/man1/dcm2xml.1
doxygen/manpages/man1/dcmcjpeg.1
doxygen/manpages/man1/dcmcjpls.1
doxygen/manpages/man1/dcmconv.1
doxygen/manpages/man1/dcmcrle.1
doxygen/manpages/man1/dcmdecap.1 [new file with mode: 0644]
doxygen/manpages/man1/dcmdjpeg.1
doxygen/manpages/man1/dcmdjpls.1
doxygen/manpages/man1/dcmdrle.1
doxygen/manpages/man1/dcmdspfn.1
doxygen/manpages/man1/dcmdump.1
doxygen/manpages/man1/dcmencap.1 [new file with mode: 0644]
doxygen/manpages/man1/dcmftest.1
doxygen/manpages/man1/dcmgpdir.1
doxygen/manpages/man1/dcmicmp.1
doxygen/manpages/man1/dcmj2pnm.1
doxygen/manpages/man1/dcml2pnm.1
doxygen/manpages/man1/dcmmkcrv.1
doxygen/manpages/man1/dcmmkdir.1
doxygen/manpages/man1/dcmmklut.1
doxygen/manpages/man1/dcmodify.1
doxygen/manpages/man1/dcmp2pgm.1
doxygen/manpages/man1/dcmprscp.1
doxygen/manpages/man1/dcmprscu.1
doxygen/manpages/man1/dcmpschk.1
doxygen/manpages/man1/dcmpsmk.1
doxygen/manpages/man1/dcmpsprt.1
doxygen/manpages/man1/dcmpsrcv.1
doxygen/manpages/man1/dcmpssnd.1
doxygen/manpages/man1/dcmqridx.1
doxygen/manpages/man1/dcmqrscp.1
doxygen/manpages/man1/dcmqrti.1
doxygen/manpages/man1/dcmquant.1
doxygen/manpages/man1/dcmrecv.1
doxygen/manpages/man1/dcmscale.1
doxygen/manpages/man1/dcmsend.1
doxygen/manpages/man1/dcmsign.1
doxygen/manpages/man1/dcod2lum.1
doxygen/manpages/man1/dconvlum.1
doxygen/manpages/man1/drtdump.1
doxygen/manpages/man1/dsr2html.1
doxygen/manpages/man1/dsr2xml.1
doxygen/manpages/man1/dsrdump.1
doxygen/manpages/man1/dump2dcm.1
doxygen/manpages/man1/echoscu.1
doxygen/manpages/man1/findscu.1
doxygen/manpages/man1/getscu.1
doxygen/manpages/man1/img2dcm.1
doxygen/manpages/man1/json2dcm.1 [new file with mode: 0644]
doxygen/manpages/man1/mkcsmapper.1
doxygen/manpages/man1/mkesdb.1
doxygen/manpages/man1/movescu.1
doxygen/manpages/man1/pdf2dcm.1
doxygen/manpages/man1/stl2dcm.1
doxygen/manpages/man1/storescp.1
doxygen/manpages/man1/storescu.1
doxygen/manpages/man1/termscu.1
doxygen/manpages/man1/wlmscpfs.1
doxygen/manpages/man1/xml2dcm.1
doxygen/manpages/man1/xml2dsr.1
oficonv/apps/mkcsmapper.y
oficonv/apps/mkcsmapper_bison.cc
oficonv/apps/mkcsmapper_bison.h
oficonv/apps/mkesdb.y
oficonv/apps/mkesdb_bison.cc
oficonv/apps/mkesdb_bison.h
oficonv/docs/oficonv.dox
oficonv/include/dcmtk/oficonv/iconv.h
oficonv/libsrc/Makefile.dep
oficonv/libsrc/citrus_bcs.c
oficonv/libsrc/citrus_bcs.h
oficonv/libsrc/citrus_big5.c
oficonv/libsrc/citrus_csmapper.c
oficonv/libsrc/citrus_db.c
oficonv/libsrc/citrus_db_factory.c
oficonv/libsrc/citrus_db_hash.c
oficonv/libsrc/citrus_dechanyu.c
oficonv/libsrc/citrus_esdb.c
oficonv/libsrc/citrus_euc.c
oficonv/libsrc/citrus_euctw.c
oficonv/libsrc/citrus_gbk2k.c
oficonv/libsrc/citrus_hash.c
oficonv/libsrc/citrus_hz.c
oficonv/libsrc/citrus_iconv.c
oficonv/libsrc/citrus_iconv.h
oficonv/libsrc/citrus_iconv_local.h
oficonv/libsrc/citrus_iconv_none.c
oficonv/libsrc/citrus_iconv_std.c
oficonv/libsrc/citrus_iso2022.c
oficonv/libsrc/citrus_jisx0208.c
oficonv/libsrc/citrus_johab.c
oficonv/libsrc/citrus_lock.h
oficonv/libsrc/citrus_lookup.c
oficonv/libsrc/citrus_mapper.c
oficonv/libsrc/citrus_mapper_zone.c
oficonv/libsrc/citrus_mmap.c
oficonv/libsrc/citrus_module.c
oficonv/libsrc/citrus_mskanji.c
oficonv/libsrc/citrus_none.c
oficonv/libsrc/citrus_region.h
oficonv/libsrc/citrus_types.h
oficonv/libsrc/citrus_utf1632.c
oficonv/libsrc/citrus_utf8.c
oficonv/libsrc/citrus_viqr.c
oficonv/libsrc/citrus_zw.c
oficonv/libsrc/oficonv_iconv.c
oficonv/libsrc/oficonv_logger.c
oficonv/tests/tests.cc
oficonv/tests/ticonv.cc
oflog/include/dcmtk/oflog/config.h
oflog/include/dcmtk/oflog/config/defines.h
oflog/include/dcmtk/oflog/config/win32.h
oflog/libsrc/fileap.cc
oflog/libsrc/log4judp.cc
oflog/libsrc/threads.cc
oflog/libsrc/timehelp.cc
ofstd/include/dcmtk/ofstd/diag/clangprg.def [new file with mode: 0644]
ofstd/include/dcmtk/ofstd/diag/vsconstexp.def [new file with mode: 0644]
ofstd/include/dcmtk/ofstd/ofchrenc.h
ofstd/include/dcmtk/ofstd/ofcmdln.h
ofstd/include/dcmtk/ofstd/ofcond.h
ofstd/include/dcmtk/ofstd/ofdate.h
ofstd/include/dcmtk/ofstd/ofdiag.h
ofstd/include/dcmtk/ofstd/offile.h
ofstd/include/dcmtk/ofstd/ofjsmn.h [new file with mode: 0644]
ofstd/include/dcmtk/ofstd/oflist.h
ofstd/include/dcmtk/ofstd/ofmath.h
ofstd/include/dcmtk/ofstd/ofmem.h
ofstd/include/dcmtk/ofstd/ofoption.h
ofstd/include/dcmtk/ofstd/ofrand.h
ofstd/include/dcmtk/ofstd/ofsha256.h [new file with mode: 0644]
ofstd/include/dcmtk/ofstd/ofsockad.h
ofstd/include/dcmtk/ofstd/ofstd.h
ofstd/include/dcmtk/ofstd/ofstdinc.h
ofstd/include/dcmtk/ofstd/ofstream.h
ofstd/include/dcmtk/ofstd/ofstrhlp.h [new file with mode: 0644]
ofstd/include/dcmtk/ofstd/oftempf.h
ofstd/include/dcmtk/ofstd/oftest.h
ofstd/include/dcmtk/ofstd/oftime.h
ofstd/include/dcmtk/ofstd/oftypes.h
ofstd/include/dcmtk/ofstd/ofvector.h
ofstd/libsrc/CMakeLists.txt
ofstd/libsrc/Makefile.dep
ofstd/libsrc/Makefile.in
ofstd/libsrc/ofconsol.cc
ofstd/libsrc/ofdatime.cc
ofstd/libsrc/offilsys.cc
ofstd/libsrc/offname.cc
ofstd/libsrc/ofipc.cc
ofstd/libsrc/ofjsmn.cc [new file with mode: 0644]
ofstd/libsrc/ofmath.cc
ofstd/libsrc/ofrand.cc
ofstd/libsrc/ofsha256.cc [new file with mode: 0644]
ofstd/libsrc/ofstd.cc
ofstd/libsrc/ofstub.cc
ofstd/libsrc/ofxml.cc
ofstd/tests/Makefile.dep
ofstd/tests/tests.cc
ofstd/tests/tstring.cc

index fd7869c78625ef1129f9db0ff69c830bcea7c332..a0034b1a2a210f1d27ff8c80a34a02ef6df6cacc 100644 (file)
@@ -29,11 +29,11 @@ jobs:
       - name: Download DCMTK Support libraries
         shell: pwsh
         run: |
-          C:\msys64\usr\bin\wget.exe -O dcmtk_support.zip https://dicom.offis.de/download/dcmtk/dcmtk368/support/dcmtk-3.6.8-win64-support-MD-msvc-17.4.zip
+          C:\msys64\usr\bin\wget.exe -O dcmtk_support.zip https://dicom.offis.de/download/dcmtk/dcmtk370/support/dcmtk-3.7.0-win64-support-MD-msvc-17.8.zip
 
       # Uncompress support libraries into directory c:\dcmtk_support\libs.
       # We rename the original directory to libs so that the rest of the script
-      # can use the ame path even if the support library package is updated
+      # can use the same path even if the support library package is updated
       # in the future in the download task above.
       - name: Uncompress Support libraries
         shell: pwsh
@@ -60,7 +60,7 @@ jobs:
           echo "Step 2"
           cd ${{ github.workspace }}\dcmtk-build
           echo "Step 3"
-          cmake -G "Visual Studio 17 2022" -Ax64 -DDCMTK_MODULES:STR="ofstd;oflog;oficonv;dcmdata;dcmimgle;dcmimage;dcmjpeg;dcmjpls;dcmtls;dcmnet;dcmsr;dcmsign;dcmwlm;dcmqrdb;dcmpstat;dcmrt;dcmiod;dcmfg;dcmseg;dcmtract;dcmpmap;dcmect" -DDCMTK_ENABLE_BUILTIN_OFICONV_DATA:BOOL=On -DBUILD_SHARED_LIBS:BOOL=ON -DDCMTK_SUPPORT_LIBRARIES_DIR:PATH=c:\dcmtk_support\libs -DCMAKE_INSTALL_PREFIX:PATH=${{ github.workspace }}\dcmtk-${{ env.NOW }}-${{ env.COMMIT_SHORT_SHA }}  ${{ github.workspace }}
+          cmake -G "Visual Studio 17 2022" -Ax64 -DDCMTK_MODULES:STR="ofstd;oflog;oficonv;dcmdata;dcmimgle;dcmimage;dcmjpeg;dcmjpls;dcmtls;dcmnet;dcmsr;dcmsign;dcmwlm;dcmqrdb;dcmpstat;dcmrt;dcmiod;dcmfg;dcmseg;dcmtract;dcmpmap;dcmect;dcmapps" -DDCMTK_ENABLE_BUILTIN_OFICONV_DATA:BOOL=On -DBUILD_SHARED_LIBS:BOOL=ON -DDCMTK_SUPPORT_LIBRARIES_DIR:PATH=c:\dcmtk_support\libs -DCMAKE_INSTALL_PREFIX:PATH=${{ github.workspace }}\dcmtk-${{ env.NOW }}-${{ env.COMMIT_SHORT_SHA }}  ${{ github.workspace }}
 
       - name: Build dcmtk
         run: |
@@ -90,7 +90,7 @@ jobs:
 
     runs-on: windows-latest
     timeout-minutes: 5
-    # Only run if the event is not a pull request and the repository owner is DCMTK.
+    # Only run if the event is not a pull request and the repository owner is michaelonken.
     # The latter is to prevent forks from publishing packages even if the owner's token
     # would have sufficient privileges.
     if: ${{ (github.event_name != 'pull_request') && (github.repository_owner == 'DCMTK')}}
@@ -118,4 +118,4 @@ jobs:
           --prerelease-packages-clear-pattern "dcmtk-*-win64.zip" `
           --prerelease-packages-keep-pattern "*<COMMIT_SHORT_SHA>*" `
           --prerelease-sha master `
-          --token ${{ secrets.RELEASE_DCMTK_TOKEN }}
\ No newline at end of file
+          --token ${{ secrets.RELEASE_DCMTK_TOKEN }}
index 89d3a277b784b329133ddfc614e0d6e46ce71d87..673736bb9748a017b6f19faec4f1216b53beb170 100644 (file)
@@ -24,6 +24,9 @@ config/autom4te.cache/
 *.*~
 *.bak
 
+# Ignore caches
+.cache
+
 # Also ignore temporary directories
 _*/
 ofstd/tests/tehtestdire/
@@ -45,13 +48,16 @@ dcmdata/apps/dcm2pdf
 dcmdata/apps/dcm2xml
 dcmdata/apps/dcmconv
 dcmdata/apps/dcmcrle
+dcmdata/apps/dcmdecap
 dcmdata/apps/dcmdrle
 dcmdata/apps/dcmdump
+dcmdata/apps/dcmencap
 dcmdata/apps/dcmftest
 dcmdata/apps/dcmgpdir
 dcmdata/apps/dcmodify
 dcmdata/apps/dump2dcm
 dcmdata/apps/img2dcm
+dcmdata/apps/json2dcm
 dcmdata/apps/pdf2dcm
 dcmdata/apps/stl2dcm
 dcmdata/apps/xml2dcm
index 646567c9ca828b06bdee01c0ae429d7487860b26..84f91b854ca131d8041ba49c53bc49feb97a58c6 100644 (file)
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,17 +1,17 @@
 ANNOUNCEMENT
 
-Version 3.6.9 of the OFFIS DCMTK (DICOM toolkit) software is now available for
+Version 3.7.0 of the OFFIS DCMTK (DICOM ToolKit) software is now available for
 public release.  This release includes the following main changes over the
-previous version 3.6.8:
+previous version 3.6.9:
 
-- DCMTK 3.6.9 builds correctly on older and up-to-date versions of GNU gcc
-  (9.5.0 to 14.2.0), Clang (14.0.6 to 18.1.8), Apple Clang (14.0.3 to 15.0.0),
+- DCMTK 3.7.0 builds correctly on older and up-to-date versions of GNU gcc
+  (10.5.0 to 14.2.0), Clang (14.0.6 to 18.1.8), Apple Clang (17.0.0),
   and Microsoft Visual Studio (2017 to 2022).
 
 - Tested with the following operating systems/environments:
   - Android on arm64
   - FreeBSD on x86_64
-  - Linux on x86_64 and x86
+  - Linux on x86_64, x86 and s390x
   - MacOS X on x86_64 and arm64
   - NetBSD on x86_64
   - OpenBSD on x86_64
@@ -22,137 +22,102 @@ previous version 3.6.8:
 
 - Updated DICOM data dictionary, list of SOP classes, well-known frame of
   references, transfer syntaxes, code definitions, supported context group
-  classes, and directory record types for DICOM standard release 2024e:
+  classes, and directory record types for DICOM standard release 2025e.
 
-  - This also includes the latest attributes and SOP classes for the DICONDE
-    standard, e.g. for thermography images (based on ASTM E3440).
+- Added initial support for the Deflated Image Frame Compression Transfer
+  Syntax, i.e. reading and writing of DICOM files and datasets that are
+  encoded with this new transfer syntax as well as basic network support.
 
-  - Also updated the DICOMDIR generation code and tools accordingly.
+- Added support for the DICONDE Storage SOP Class for ultrasonic waveforms
+  introduced with DICOM 2025b (based on a revised version of ASTM E2663).
 
+- Added support for creating, writing and reading Labelmap Segmentation Storage
+  objects to the "dcmseg" module.
 
-- The new JPEG XL and HTJ2K transfer syntaxes as well as the encapsulated
-  uncompressed transfer syntax are now supported for reading and writing, i.e.
-  for both files and network transfer.  However, encoders or decoders have not
-  been implemented yet.
+- Added new command line tools "dcmencap" and "dcmdecap" that handle the
+  encapsulation and decapsulation of all currently defined Encapsulated
+  Document Storage SOP Classes in DICOM.  The older tools "pdf2dcm", "cda2dcm",
+  "stl2dcm", "dcm2pdf" and "dcm2cda" are now deprecated and will be removed in
+  a future version of DCMTK.
 
-- Added new command line tool dcm2img that unifies and replaces the tools
-  dcm2pnm, dcmj2pnm and dcml2pnm, and adds support for JPEG-LS as an export
-  format for image files.  The command line options are identical to the older
-  tools, so that dcm2img can serve as a drop-in replacement:
+- Added new command line tool "json2dcm" that converts the contents of a DICOM
+  dataset in JSON encoding to a binary DICOM file or dataset.  The JSON
+  document is expected to conform to the "DICOM JSON Model" as defined in
+  DICOM Part 18, Section F.
 
-  - By default, the new command line tool determines the output format
-    automatically based on the extension of the output filename.
+- The command line tool "dcm2json" can now create BulkDataURIs and related bulk
+  data files.
 
-  - The deprecated command line tools were replaced by stubs, which are provided
-    for the user's convenience, but will be removed with a future release.
+- Improved the handling of JPEG image files as input to "img2dcm".  Several
+  special cases such as different types of component subsampling, or lossy JPEG
+  images in RGB or CMYK color (instead of YCbCr) are now correctly handled.
 
-- Added new command line tool dcm2cda that extracts a CDA document from a DICOM
-  Encapsulated CDA Storage SOP Instance and stores it in a separate file.
+- The "storescp" tool can now limit the number of network associations handled
+  in parallel when operating in "fork mode", on all supported platforms.
 
-- Replaced command line tool dcmgpdir by a stub that calls the more
-  comprehensive command line tool dcmmkdir.
+- Enhanced Specific Character Set support of the command line tool "dcm2xml"
+  when converting DICOMDIR files.
 
-- Further enhanced and updated DICOM Structured Reporting (SR) module "dcmsr":
+- Added support for the optional Patient's Age attribute from the Patient
+  Study Module to the "dcmsr" module.  This attribute is now written to and
+  read from a DICOM dataset as well as to/from the "dcmsr"-specific XML
+  document format (see "dsr2xml.xsd").
 
-  - Added support for the new Waveform Annotation SR IOD (introduced with
-    Supplement 239).
+- Enhanced support for TLS in command line tools "dcmqrscp" and "movescu".
+  Query/Retrieve can now be completely performed over TLS.
 
-  - Made URL prefix for hyperlinks to composite objects configurable.
+- Added support for IPv6 in DCMTK's association acceptors.  The support for
+  DICOM network connections over IPv6 is now considered complete.  Both
+  association requestors and association acceptors can choose between IPv4
+  only, IPv6 only, and dual-stack mode.  The default behavior of the command
+  line tools is unchanged (i.e. IPv4 only.)
 
-  - Updated code definitions and supported context group classes (see above).
+- Added APIs that allows the user to set the Implementation Class UID and
+  Implementation Version Name at runtime while writing a DICOM file, processing
+  an incoming network association request or configuring an outgoing network
+  association request.
 
-  - Fixed issue with various IOD constraint checkers (see CP-2084).
+- Added "putAndInsertXXX()" helper methods for the still rather new 64-bit VRs
+  "SV", "UV" and "OV" to the "DcmItem" class.
 
-- Added IPv6 support to DCMTK's association requestors.  All DCMTK "client"
-  applications that only request outgoing DICOM network associations can now
-  explicitly select the protocol version to be used.  IPv6 support is not yet
-  implemented for association acceptors ("server" applications).
+- Improved handling of invalid DICOM images when processing with the
+  "DicomImage" class or the "dcm2img" command line tool.
 
-- Various TLS enhancements:
+- Improved performance of the "DcmList" class that is used internally for the
+  DICOM dataset parser.
 
-  - Added TLS support to the command line tools dcmqrscp and getscu.
+- Further clean-up of configure tests that checked for features that are not
+  used anymore in DCMTK or that are not in use anymore on any of the supported
+  operating systems (e.g. pre-POSIX APIs and header files).
 
-  - Added support for the Modified BCP 195 RFC 8996 TLS Profile.
-
-  - Added new command line option --list-profiles to all TLS-enabled tools.
-    This option prints a list of the TLS Secure Transport Connection Profiles
-    supported.
-
-  - Removed support for OpenSSL 1.0.2 and 1.1.0 and added support for OpenSSL
-    3.1.0 to 3.4.0.
-
-- Extended central DCMTK data structure where all SOP Classes are defined with
-  their associated properties, e.g. type and sub-type.
-
-- Largely enhanced basic transfer syntax class DcmXfer, e.g. to distinguish
-  more clearly between encapsulation and compression.  Please note that some of
-  the old methods have been deprecated and will be removed in a future release.
-
-- Enhanced performance of OFGlobal class, especially when used in applications
-  with many threads that read global objects of this class concurrently.
-
-- New, fully standards compliant implementations of OFStandard::atof() and
-  OFStandard::ftoa(), DCMTK's locale independent conversion routines between
-  floating point numbers and text.
-
-- Removed support for ICU-based character set conversion.  Since the oficonv
-  module in DCMTK supports all DICOM Specific Character Sets, the ICU support,
-  which was never complete, has been removed.
-
-- DCMTK now requires compilers to provide conformance to C++98 and supports
-  compilation with newer C++ versions up to C++20, which can be enabled via
-  CMake's CMAKE_CXX_STANDARD variable.  By default, C++11 is now enabled on
-  compilers that support this.
-
-- CMake-related enhancements and other changes:
-
-  - The configure process now respects CMake's CMAKE_CROSSCOMPILING_EMULATOR
-    variable.
-
-  - Exposed the CMAKE_DEBUG_POSTFIX variable to the user.  There are extra
-    options to also enable the postfix for Windows DLLs as well as executables.
-
-- Many configure tests related to outdated compilers or libraries were removed,
-  thus significantly speeding up the configuration process.
-
-- Fixed binary segmentations with certain dimensions (some cases where number
-  of total bits per frame is not divisible by 8) that were broken when being
-  serialized into a dataset.
-
-- Fixed various other issues that occurred after the official 3.6.8 release,
+- Fixed various other issues that occurred after the official 3.6.9 release,
   and further improved the performance.  See CHANGES file for details.
 
 Many people have contributed to this new release of DCMTK, appearing here in
 alphabetical order.  Thank you very much for your support!
 
-  Christian Wetzel <wetzel@phoenix-pacs.de>
-  David Gobbi <david.gobbi@gmail.com>
-  David Seifert <soap@gentoo.org>
-  Giulio Simonetti <giulio.simonetti@datamind.biz>
-  Helmut Steiner <helmut@shl.at>
-  Jean Pierre Bassenge <jp.bassenge@fiagon.com>
+  Ben Chen <Ben.Chen@intusurg.com>
+  Chuang Zhao <zhaocccchuang@163.com>
+  Ding zhengzheng <xiaozheng.ding399@gmail.com>
+  Drak <dr4k.sec@gmail.com>
+  Emmanuel Tacheau of the Cisco Talos team <vulndiscovery@external.cisco.com>
   Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
-  Jesper Alf Dam <Jesper.Dam@mi.medical.canon>
-  Kevin Leonardic <kevin@leonardic.de>
-  Marcel Pham <Marcel.Pham@examion.com>
-  Mario Galijot <mario@salaourn.com>
-  Markus Sabin <Markus.Sabin@soft-gate.de>
-  Martin Zeiser of the Cisco Talos team <vulndiscovery@external.cisco.com>
+  Jez Cooke <jez.cooke@hamamatsu.eu>
+  Kade Rashid <kade.rashid@hamamatsu.eu>
+  Khang Tran <khangthk@gmail.com>
   Mathieu Malaterre <mathieu.malaterre@gmail.com>
-  Matt McCormick <matt.mccormick@kitware.com>
-  Melanie Michels <melanie.michels@snkeos.com>
-  Nils Bars <nils.bars@rub.de>
-  Peter Klotz <peter.klotz@siemens-healthineers.com>
-  Phileas Lebada <phileas@contextflow.com>
-  Piotr Batko <Piotr.Batko@gehealthcare.com>
-  Sam James <sam@gentoo.org>
+  Matt Hancock <mhancock@innolitics.com>
+  Oliver Klerx <klerx@phoenix-pacs.de>
+  Simeon Stoykov <simeon@microdicom.com>
   Sobhita Mercy <sobhitamercy@gmail.com>
-  Yoshinaga Kosuke <kosuke.yoshinaga@goodmankk.com>
+  Vasyl Horbatenko (GitHub user doskachok)
+  Zou Dikai <zoudikai@outlook.com>
 
-  DCMTK forum users "andreasb", "Fabian Guenther", "nbeck", "Oleh", "saltcreek"
+  DCMTK forum users "cschreib", "hapap", "OliWe", "pierrechatelier",
+    "pintagliata", "saltcreek" and "Shaeto"
 
-  GitHub users "akaraivanov", "bananabr", "khangthk", "luissantosHCIT",
-    "malaterre", "mrbean-bremen", "percontation", "thewtex"
+  GitHub users "luk1337", "mrbean-bremen", "nbeck-SMT", "Oss-Auditor",
+    "parasite-lost", "reunanen" and "Vovasch"
 
 Members of the DCMTK Team who have worked on this release are:
 
@@ -165,4 +130,4 @@ The DCMTK software can be downloaded via:
 
   https://dicom.offis.de/dcmtk or https://www.dcmtk.org/
 
-OFFIS e.V., Oldenburg, Germany, 2024-12-10
+OFFIS e.V., Oldenburg, Germany, 2025-12-15
index 510027c849ebec34f025a1f82d74f7364f7ef689..837900575bf700adbe1b793993d0d913a8fb1c1e 100644 (file)
@@ -58,7 +58,7 @@ if(DCMTK_USE_FIND_PACKAGE)
       message(STATUS "Info: DCMTK PNG support will be enabled")
       set(WITH_LIBPNG 1)
       include_directories(${PNG_INCLUDE_DIR})
-      set(LIBPNG_LIBS ${PNG_LIBRARY})
+      set(LIBPNG_LIBS ${PNG_LIBRARY} ${LIBPNG_EXTRA_LIBS_STATIC})
     endif()
   endif()
 
@@ -249,8 +249,8 @@ else()
       set(LIBXML_INCDIR "${WITH_LIBXMLINC}/include")
       set(LIBXML_LIBDIR "${WITH_LIBXMLINC}/lib")
       # libxml2 2.13 and newer require bcrypt.lib on Windows.
-      set(LIBXML_LIBS bcrypt debug "${LIBXML_LIBDIR}/libxml2_d.lib" optimized "${LIBXML_LIBDIR}/libxml2_o.lib")
-      if (EXISTS "${LIBXML_LIBDIR}/iconv_o.lib")
+      set(LIBXML_LIBS bcrypt debug "${LIBXML_LIBDIR}/libxml2_d.lib" optimized "${LIBXML_LIBDIR}/libxml2_o.lib" ${LIBXML2_EXTRA_LIBS_STATIC})
+      if(EXISTS "${LIBXML_LIBDIR}/iconv_o.lib")
           set(LIBXML_LIBS ${LIBXML_LIBS} debug "${LIBXML_LIBDIR}/iconv_d.lib" optimized "${LIBXML_LIBDIR}/iconv_o.lib")
       endif()
       message(STATUS "Info: DCMTK XML support will be enabled")
@@ -269,7 +269,7 @@ else()
     if(WITH_LIBPNGINC)
       set(LIBPNG_INCDIR "${WITH_LIBPNGINC}/include")
       set(LIBPNG_LIBDIR "${WITH_LIBPNGINC}/lib")
-      set(LIBPNG_LIBS debug "${LIBPNG_LIBDIR}/libpng_d.lib" optimized "${LIBPNG_LIBDIR}/libpng_o.lib")
+      set(LIBPNG_LIBS debug "${LIBPNG_LIBDIR}/libpng_d.lib" optimized "${LIBPNG_LIBDIR}/libpng_o.lib" ${LIBPNG_EXTRA_LIBS_STATIC})
       message(STATUS "Info: DCMTK PNG support will be enabled")
       set(WITH_LIBPNG 1)
     else() # turn off library if library path not set
@@ -284,7 +284,7 @@ else()
     if(WITH_LIBTIFFINC)
       set(LIBTIFF_INCDIR "${WITH_LIBTIFFINC}/include")
       set(LIBTIFF_LIBDIR "${WITH_LIBTIFFINC}/lib")
-      set(LIBTIFF_LIBS debug "${LIBTIFF_LIBDIR}/libtiff_d.lib" optimized "${LIBTIFF_LIBDIR}/libtiff_o.lib")
+      set(LIBTIFF_LIBS debug "${LIBTIFF_LIBDIR}/libtiff_d.lib" optimized "${LIBTIFF_LIBDIR}/libtiff_o.lib" ${TIFF_EXTRA_LIBS_STATIC})
       message(STATUS "Info: DCMTK TIFF support will be enabled")
       set(WITH_LIBTIFF 1)
     else() # turn off library if library path not set
@@ -302,7 +302,7 @@ else()
       set(OPENSSL_INCDIR "${WITH_OPENSSLINC}/include")
       set(OPENSSL_LIBDIR "${WITH_OPENSSLINC}/lib")
       # starting with OpenSSL 1.1.0, the Windows crypt32 library is needed for a static link of OpenSSL.
-      set(OPENSSL_LIBS "crypt32" debug "${OPENSSL_LIBDIR}/dcmtkssl_d.lib" optimized "${OPENSSL_LIBDIR}/dcmtkssl_o.lib" debug "${OPENSSL_LIBDIR}/dcmtkcrypto_d.lib" optimized "${OPENSSL_LIBDIR}/dcmtkcrypto_o.lib")
+      set(OPENSSL_LIBS "crypt32" debug "${OPENSSL_LIBDIR}/dcmtkssl_d.lib" optimized "${OPENSSL_LIBDIR}/dcmtkssl_o.lib" debug "${OPENSSL_LIBDIR}/dcmtkcrypto_d.lib" optimized "${OPENSSL_LIBDIR}/dcmtkcrypto_o.lib" ${OPENSSL_EXTRA_LIBS_STATIC})
       set(TEMP_INCLUDES "${CMAKE_REQUIRED_INCLUDES}")
       list(APPEND CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCDIR}")
       CHECK_CXX_SOURCE_COMPILES("extern \"C\" {\n#include <openssl/ssl.h>\n}\nint main(){\n#if OPENSSL_VERSION_NUMBER < 0x10001000L\n#error OpenSSL too old\n#endif\n}\n" OPENSSL_VERSION_CHECK)
@@ -342,7 +342,7 @@ else()
     if(WITH_SNDFILEINC)
       set(SNDFILE_INCDIR "${WITH_SNDFILEINC}/include")
       set(SNDFILE_LIBDIR "${WITH_SNDFILEINC}/lib")
-      set(SNDFILE_LIBS debug "${SNDFILE_LIBDIR}/libsndfile_d.lib" optimized "${SNDFILE_LIBDIR}/libsndfile_o.lib")
+      set(SNDFILE_LIBS debug "${SNDFILE_LIBDIR}/libsndfile_d.lib" optimized "${SNDFILE_LIBDIR}/libsndfile_o.lib" ${SNDFILE_EXTRA_LIBS_STATIC})
       message(STATUS "Info: DCMTK SNDFILE support will be enabled")
       set(WITH_SNDFILE 1)
     else() # turn off library if library path not set
@@ -373,14 +373,14 @@ else()
       # Unfortunately, OpenJPEG uses a version number in the include path. This needs special handling.
       file(GLOB OPENJPEG2_DIR "${WITH_OPENJPEGINC}/include/openjpeg*")
       find_path(WITH_OPENJPEGINC1 "openjpeg.h" "${OPENJPEG2_DIR}" NO_DEFAULT_PATH)
-      if ("${WITH_OPENJPEGINC1}" STREQUAL "WITH_OPENJPEGINC1-NOTFOUND")
+      if("${WITH_OPENJPEGINC1}" STREQUAL "WITH_OPENJPEGINC1-NOTFOUND")
           message(STATUS "Info: DCMTK OpenJPEG support will be disabled because the header files were not found.")
           set(DCMTK_WITH_OPENJPEG OFF CACHE BOOL "" FORCE)
           set(WITH_OPENJPEG "")
       else()
           set(OPENJPEG_INCDIR "${WITH_OPENJPEGINC1}")
           set(OPENJPEG_LIBDIR "${WITH_OPENJPEGINC}/lib")
-          set(OPENJPEG_LIBS debug "${OPENJPEG_LIBDIR}/openjp2_d.lib" optimized "${OPENJPEG_LIBDIR}/openjp2_o.lib")
+          set(OPENJPEG_LIBS debug "${OPENJPEG_LIBDIR}/openjp2_d.lib" optimized "${OPENJPEG_LIBDIR}/openjp2_o.lib" ${OPENJPEG_EXTRA_LIBS_STATIC})
           message(STATUS "Info: DCMTK OpenJPEG support will be enabled")
           set(WITH_OPENJPEG 1)
       endif()
index 087bb7aa3cd0634f3b4f5d4f6c024c4a0fa87a29..08ef1d621ec64599ea19038fc2aa78022ceb6d6b 100644 (file)
@@ -5,7 +5,7 @@
 #
 
 # Restore the required settings of the CMake configuration step
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.7.0...4.2.0 FATAL_ERROR)
 set(CMAKE_COMMAND "@CMAKE_COMMAND@")
 set(CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@")
 set(CMAKE_CURRENT_BINARY_DIR "@CMAKE_BINARY_DIR@")
@@ -16,15 +16,18 @@ set(CMAKE_SHARED_LIBRARY_SUFFIX "@CMAKE_SHARED_LIBRARY_SUFFIX@")
 set(CMAKE_HOST_SYSTEM "@CMAKE_HOST_SYSTEM@")
 set(DCMTK_CMAKE_INCLUDE "@CMAKE_SOURCE_DIR@/@DCMTK_CMAKE_INCLUDE@")
 set(DCMTK_TEST_EXECUTABLES "@DCMTK_TEST_EXECUTABLES@")
+set(DCMTK_TEST_EXECUTABLE_PATH "@DCMTK_TEST_EXECUTABLE_PATH@")
 set(DCMTK_ALL_LIBRARIES "@DCMTK_ALL_LIBRARIES@")
 set(DCMTK_LIBRARY_DEPENDENCIES "@DCMTK_LIBRARY_DEPENDENCIES@")
 set(DCMTK_PACKAGE_VERSION "@DCMTK_PACKAGE_VERSION@")
 set(DCMTK_ABI_VERSION "@DCMTK_ABI_VERSION@")
 set(BUILD_SHARED_LIBS "@BUILD_SHARED_LIBS@")
 set(DCMTK_DICOM_DICTIONARIES "@DCMTK_DICOM_DICTIONARIES@")
+set(DCMTK_ICONV_DATAFILES "@DCMTK_ICONV_DATAFILES@")
 set(ANDROID "@ANDROID@")
+set(ANDROID_EMULATOR_PORT "@ANDROID_EMULATOR_PORT@")
 set(ANDROID_ADB_PROGRAM "@ANDROID_ADB_PROGRAM@")
-set(ANDROID_ANDROID_PROGRAM "@ANDROID_ANDROID_PROGRAM@")
+set(ANDROID_AVDMANAGER_PROGRAM "@ANDROID_AVDMANAGER_PROGRAM@")
 set(ANDROID_EMULATOR_PROGRAM "@ANDROID_EMULATOR_PROGRAM@")
 set(ANDROID_EMULATOR_AVD "@ANDROID_EMULATOR_AVD@")
 set(ANDROID_RUNTIME_LIBRARIES "@ANDROID_RUNTIME_LIBRARIES@")
@@ -71,13 +74,14 @@ DCMTK_ANDROID_PUSH(DCMTK_ANDROID_EMULATOR_INSTANCE
     ${ANDROID_RUNTIME_LIBRARIES}
     ${DCMTK_LIBRARY_DEPENDENCIES}
     ${DCMTK_CREATED_SHARED_LIBRARIES}
-    ${DCMTK_TEST_EXECUTABLES}
+    ${DCMTK_TEST_EXECUTABLE_PATH}
     ${DCMTK_DICOM_DICTIONARIES}
+    ${DCMTK_ICONV_DATAFILES}
     DESTINATION ${ANDROID_TEMPORARY_FILES_LOCATION}
 )
 
 # Set executable permissions
-foreach(TEST_EXECUTABLE ${DCMTK_TEST_EXECUTABLES})
+foreach(TEST_EXECUTABLE ${DCMTK_TEST_EXECUTABLE_PATH})
     get_filename_component(NAME "${TEST_EXECUTABLE}" NAME)
     DCMTK_ANDROID_SHELL(DCMTK_ANDROID_EMULATOR_INSTANCE
         COMMAND chmod 755 "${ANDROID_TEMPORARY_FILES_LOCATION}/${NAME}"
index c9d7663cfb4de4253b71d5c0aad32426b7a6efa4..eda050757639bae1a2de0110e5829c4fd7b74433 100644 (file)
@@ -22,7 +22,7 @@ set(DCMTK_ANDROID_EMULATOR_INSTANCE "$ENV{DCMTK_ANDROID_EMULATOR_INSTANCE}")
 
 # Run the actual testcase on the remote device
 DCMTK_ANDROID_SHELL(DCMTK_ANDROID_EMULATOR_INSTANCE
-    COMMAND "LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${ANDROID_TEMPORARY_FILES_LOCATION}" "DCMDICTPATH=${DCMDICTPATH}" "${DCMTK_CTEST_TESTCASE_COMMAND}" $ENV{DCMTK_CTEST_EXTRA_ARGUMENTS} "${DCMTK_CTEST_TEST_NAME}"
+  COMMAND "LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${ANDROID_TEMPORARY_FILES_LOCATION}" "DCMDICTPATH=${DCMDICTPATH}" "DCMICONVPATH=${DCMICONVPATH}" "${DCMTK_CTEST_TESTCASE_COMMAND}" $ENV{DCMTK_CTEST_EXTRA_ARGUMENTS} "${DCMTK_CTEST_TEST_NAME}"
     WORKING_DIRECTORY "${ANDROID_TEMPORARY_FILES_LOCATION}"
     RESULT_VARIABLE RESULT
 )
index 9ae5cfce4dcd99f25c7196f02f102e844dd7649d..88f73c84792ee0fe456b210a8a756aee5f3da3cf 100644 (file)
@@ -69,7 +69,6 @@ set(DCMTK_WIDE_CHAR_MAIN_FUNCTION @DCMTK_WIDE_CHAR_MAIN_FUNCTION@)
 set(DCMTK_ENABLE_LFS @DCMTK_ENABLE_LFS@)
 set(DCMTK_ENABLE_CHARSET_CONVERSION @DCMTK_ENABLE_CHARSET_CONVERSION@)
 
-
 # CMake builtins
 set(DCMTK_CMAKE_BUILD_TYPE @CMAKE_BUILD_TYPE@)
 set(DCMTK_CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
@@ -92,15 +91,17 @@ set(DCMTK_CMAKE_EXE_LINKER_FLAGS_RELEASE @CMAKE_EXE_LINKER_FLAGS_RELEASE@)
 set(DCMTK_CMAKE_EXE_LINKER_FLAGS_MINSIZEREL @CMAKE_EXE_LINKER_FLAGS_MINSIZEREL@)
 set(DCMTK_CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO @CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO@)
 
-set(DCMTK_CMAKE_INSTALL_BINDIR @CMAKE_INSTALL_BINDIR@)
-set(DCMTK_CMAKE_INSTALL_SYSCONFDIR @CMAKE_INSTALL_SYSCONFDIR@)
-set(DCMTK_CMAKE_INSTALL_INCLUDEDIR @CMAKE_INSTALL_INCLUDEDIR@)
-set(DCMTK_CMAKE_INSTALL_LIBDIR @CMAKE_INSTALL_LIBDIR@)
-set(DCMTK_CMAKE_INSTALL_DATAROOTDIR @CMAKE_INSTALL_DATAROOTDIR@)
+# DCMTK installation directories
+set(DCMTK_CMAKE_INSTALL_BINDIR "@CMAKE_INSTALL_BINDIR@")
+set(DCMTK_CMAKE_INSTALL_SYSCONFDIR "@CMAKE_INSTALL_SYSCONFDIR@")
+set(DCMTK_CMAKE_INSTALL_INCLUDEDIR "@CMAKE_INSTALL_INCLUDEDIR@")
+set(DCMTK_CMAKE_INSTALL_LIBDIR "@CMAKE_INSTALL_LIBDIR@")
+set(DCMTK_CMAKE_INSTALL_DATAROOTDIR "@CMAKE_INSTALL_DATAROOTDIR@")
+set(DCMTK_CMAKE_INSTALL_DATADIR "@CMAKE_INSTALL_DATADIR@")
+set(DCMTK_CMAKE_INSTALL_DOCDIR "@CMAKE_INSTALL_DOCDIR@")
 
 set(DCMTK_CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@")
 
-
 SET_AND_CHECK(DCMTK_TARGETS "@PACKAGE_DCMTK_CMKDIR_CONFIG@/DCMTKTargets.cmake")
 
 @DCMTK_CONFIG_CODE@
index a3856d3d078e02b19f06480b8c8ae8135eb4e471..ac3ae70aabe280e577c7700322346c7d09dc8bd2 100644 (file)
@@ -126,7 +126,7 @@ DCMTK_UNSET(SYSTEM_PROCESSOR)
 
 # Define the complete package version name that will be used as a subdirectory
 # name for the installation of configuration files, data files and documents.
-if (DCMTK_PACKAGE_VERSION_SUFFIX STREQUAL "+")
+if(DCMTK_PACKAGE_VERSION_SUFFIX STREQUAL "+")
   # development version
   set(DCMTK_COMPLETE_PACKAGE_VERSION "${DCMTK_PACKAGE_VERSION}-${DCMTK_PACKAGE_DATE}")
 else()
@@ -226,12 +226,9 @@ else()
 endif()
 
 # Check the sizes of various types
-include (CheckTypeSize)
-CHECK_TYPE_SIZE("double" SIZEOF_DOUBLE)
-CHECK_TYPE_SIZE("float" SIZEOF_FLOAT)
+include(CheckTypeSize)
 CHECK_TYPE_SIZE("int" SIZEOF_INT)
 CHECK_TYPE_SIZE("long" SIZEOF_LONG)
-CHECK_TYPE_SIZE("short" SIZEOF_SHORT)
 CHECK_TYPE_SIZE("void*" SIZEOF_VOID_P)
 
 # Check for include files, libraries, and functions
@@ -304,14 +301,12 @@ endif()
   CHECK_INCLUDE_FILE_CXX("cstdint" HAVE_CSTDINT)
   CHECK_INCLUDE_FILE_CXX("dirent.h" HAVE_DIRENT_H)
   CHECK_INCLUDE_FILE_CXX("err.h" HAVE_ERR_H)
-  CHECK_INCLUDE_FILE_CXX("fcntl.h" HAVE_FCNTL_H)
   CHECK_INCLUDE_FILE_CXX("fnmatch.h" HAVE_FNMATCH_H)
   CHECK_INCLUDE_FILE_CXX("grp.h" HAVE_GRP_H)
   CHECK_INCLUDE_FILE_CXX("ieeefp.h" HAVE_IEEEFP_H)
   CHECK_INCLUDE_FILE_CXX("io.h" HAVE_IO_H)
   CHECK_INCLUDE_FILE_CXX("langinfo.h" HAVE_LANGINFO_H)
   CHECK_INCLUDE_FILE_CXX("libc.h" HAVE_LIBC_H)
-  CHECK_INCLUDE_FILE_CXX("malloc.h" HAVE_MALLOC_H)
   CHECK_INCLUDE_FILE_CXX("mqueue.h" HAVE_MQUEUE_H)
   CHECK_INCLUDE_FILE_CXX("netdb.h" HAVE_NETDB_H)
   CHECK_INCLUDE_FILE_CXX("png.h" HAVE_PNG_H)
@@ -319,7 +314,6 @@ endif()
   CHECK_INCLUDE_FILE_CXX("pthread.h" HAVE_PTHREAD_H)
   CHECK_INCLUDE_FILE_CXX("pwd.h" HAVE_PWD_H)
   CHECK_INCLUDE_FILE_CXX("semaphore.h" HAVE_SEMAPHORE_H)
-  CHECK_INCLUDE_FILE_CXX("stdint.h" HAVE_STDINT_H)
   CHECK_INCLUDE_FILE_CXX("strings.h" HAVE_STRINGS_H)
   CHECK_INCLUDE_FILE_CXX("synch.h" HAVE_SYNCH_H)
   CHECK_INCLUDE_FILE_CXX("sys/dir.h" HAVE_SYS_DIR_H)
@@ -332,12 +326,10 @@ endif()
   CHECK_INCLUDE_FILE_CXX("sys/resource.h" HAVE_SYS_RESOURCE_H)
   CHECK_INCLUDE_FILE_CXX("sys/select.h" HAVE_SYS_SELECT_H)
   CHECK_INCLUDE_FILE_CXX("sys/socket.h" HAVE_SYS_SOCKET_H)
-  CHECK_INCLUDE_FILE_CXX("sys/stat.h" HAVE_SYS_STAT_H)
   CHECK_INCLUDE_FILE_CXX("sys/syscall.h" HAVE_SYS_SYSCALL_H)
   CHECK_INCLUDE_FILE_CXX("sys/systeminfo.h" HAVE_SYS_SYSTEMINFO_H)
   CHECK_INCLUDE_FILE_CXX("sys/time.h" HAVE_SYS_TIME_H)
   CHECK_INCLUDE_FILE_CXX("sys/timeb.h" HAVE_SYS_TIMEB_H)
-  CHECK_INCLUDE_FILE_CXX("sys/types.h" HAVE_SYS_TYPES_H)
   CHECK_INCLUDE_FILE_CXX("sys/un.h" HAVE_SYS_UN_H)
   CHECK_INCLUDE_FILE_CXX("sys/utime.h" HAVE_SYS_UTIME_H)
   CHECK_INCLUDE_FILE_CXX("sys/utsname.h" HAVE_SYS_UTSNAME_H)
@@ -347,8 +339,6 @@ endif()
   CHECK_INCLUDE_FILE_CXX("unistd.h" HAVE_UNISTD_H)
   CHECK_INCLUDE_FILE_CXX("unix.h" HAVE_UNIX_H)
   CHECK_INCLUDE_FILE_CXX("utime.h" HAVE_UTIME_H)
-  CHECK_INCLUDE_FILE_CXX("system_error" HAVE_SYSTEM_ERROR)
-  CHECK_INCLUDE_FILE_CXX("tuple" HAVE_TUPLE)
   CHECK_INCLUDE_FILE_CXX("type_traits" HAVE_TYPE_TRAITS)
   CHECK_INCLUDE_FILE_CXX("atomic" HAVE_ATOMIC)
 
@@ -363,11 +353,8 @@ endif()
 
   # This mimics the autoconf test. There are systems out there
   # (e.g. FreeBSD and NeXT) where tcp.h can't be compiled on its own.
-  set(TCP_H_DEPS "")
-  if(HAVE_SYS_TYPES_H)
-    # This one is needed to make FreeBSD happy
-    set(TCP_H_DEPS "sys/types.h")
-  endif()
+  # This one is needed to make FreeBSD happy
+  set(TCP_H_DEPS "sys/types.h")
   CHECK_INCLUDE_FILES("${TCP_H_DEPS};netinet/in_systm.h" HAVE_NETINET_IN_SYSTM_H)
   if(HAVE_NETINET_IN_SYSTM_H)
     set(TCP_H_DEPS "${TCP_H_DEPS};netinet/in_systm.h")
@@ -393,9 +380,6 @@ endif()
     set(HAVE_NO_TYPEDEF_PID_T TRUE)
   else()
     set(HAVE_NO_TYPEDEF_PID_T FALSE)
-    if(NOT ${HAVE_SYS_TYPES_H})
-      set(HAVE_NO_TYPEDEF_SSIZE_T TRUE)
-    endif()
   endif()
 
   set(HEADERS)
@@ -431,11 +415,7 @@ endif()
   endif()
 
   set(HEADERS ${HEADERS} stdlib.h)
-
-  if(HAVE_STDINT_H)
-    set(HEADERS ${HEADERS} stdint.h)
-  endif()
-
+  set(HEADERS ${HEADERS} stdint.h)
   set(HEADERS ${HEADERS} stddef.h)
 
   if(HAVE_NETDB_H)
@@ -464,17 +444,13 @@ endif()
     set(HEADERS ${HEADERS} sys/resource.h)
   endif()
 
-  if(HAVE_SYS_TYPES_H)
-    set(HEADERS ${HEADERS} sys/types.h)
-  endif()
+  set(HEADERS ${HEADERS} sys/types.h)
 
   if(HAVE_SYS_SOCKET_H)
     set(HEADERS ${HEADERS} sys/socket.h)
   endif()
 
-  if(HAVE_SYS_STAT_H)
-    set(HEADERS ${HEADERS} sys/stat.h)
-  endif()
+  set(HEADERS ${HEADERS} sys/stat.h)
 
   if(HAVE_SYS_TIMEB_H)
     set(HEADERS ${HEADERS} sys/timeb.h)
@@ -514,9 +490,7 @@ endif()
     set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} iphlpapi ws2_32 netapi32 wsock32)
   endif()
 
-  if(HAVE_FENV_H)
-    set(HEADERS ${HEADERS} fenv.h)
-  endif()
+  set(HEADERS ${HEADERS} fenv.h)
 
   # std::vsnprintf and std::vsnprintf need the C++ version of the headers.
   # We just assume they exist when the C version was found
@@ -541,12 +515,9 @@ endif()
 
   CHECK_FUNCTION_EXISTS(_findfirst HAVE__FINDFIRST)
   CHECK_FUNCTION_EXISTS(_set_output_format HAVE__SET_OUTPUT_FORMAT)
-  CHECK_FUNCTION_EXISTS(access HAVE_ACCESS)
   CHECK_FUNCTION_EXISTS(atoll HAVE_ATOLL)
-  CHECK_FUNCTION_EXISTS(bcmp HAVE_BCMP)
   CHECK_FUNCTION_EXISTS(cuserid HAVE_CUSERID)
   CHECK_FUNCTION_EXISTS(fgetln HAVE_FGETLN)
-  CHECK_FUNCTION_EXISTS(finite HAVE_FINITE)
   CHECK_FUNCTION_EXISTS(flock HAVE_FLOCK)
   CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
   CHECK_FUNCTION_EXISTS(fseeko HAVE_FSEEKO)
@@ -558,27 +529,18 @@ endif()
   CHECK_FUNCTION_EXISTS(gethostid HAVE_GETHOSTID)
   CHECK_FUNCTION_EXISTS(getlogin HAVE_GETLOGIN)
   CHECK_FUNCTION_EXISTS(getlogin_r HAVE_GETLOGIN_R)
-  CHECK_FUNCTION_EXISTS(getpid HAVE_GETPID)
   CHECK_FUNCTION_EXISTS(getpwnam HAVE_GETPWNAM)
-  CHECK_FUNCTION_EXISTS(getrusage HAVE_GETRUSAGE)
   CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
   CHECK_FUNCTION_EXISTS(getuid HAVE_GETUID)
   CHECK_FUNCTION_EXISTS(gmtime_r HAVE_GMTIME_R)
-  CHECK_FUNCTION_EXISTS(index HAVE_INDEX)
-  CHECK_FUNCTION_EXISTS(itoa HAVE_ITOA)
-  CHECK_FUNCTION_EXISTS(listen HAVE_LISTEN)
   CHECK_FUNCTION_EXISTS(localtime_r HAVE_LOCALTIME_R)
   CHECK_FUNCTION_EXISTS(lockf HAVE_LOCKF)
   CHECK_FUNCTION_EXISTS(lstat HAVE_LSTAT)
   CHECK_FUNCTION_EXISTS(malloc_debug HAVE_MALLOC_DEBUG)
   CHECK_FUNCTION_EXISTS(mkstemp HAVE_MKSTEMP)
-  CHECK_FUNCTION_EXISTS(mktemp HAVE_MKTEMP)
   CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP)
-  CHECK_FUNCTION_EXISTS(rindex HAVE_RINDEX)
   CHECK_FUNCTION_EXISTS(setuid HAVE_SETUID)
   CHECK_FUNCTION_EXISTS(sleep HAVE_SLEEP)
-  CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
-  CHECK_FUNCTION_EXISTS(strdup HAVE_STRDUP)
   CHECK_FUNCTION_EXISTS(strlcat HAVE_STRLCAT)
   CHECK_FUNCTION_EXISTS(strlcpy HAVE_STRLCPY)
   CHECK_FUNCTION_EXISTS(sysinfo HAVE_SYSINFO)
@@ -588,10 +550,6 @@ endif()
 
   CHECK_SYMBOL_EXISTS(strcasestr "string.h" HAVE_PROTOTYPE_STRCASESTR)
 
-  CHECK_FUNCTIONWITHHEADER_EXISTS(feenableexcept "${HEADERS}" HAVE_PROTOTYPE_FEENABLEEXCEPT)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(finite "${HEADERS}" HAVE_PROTOTYPE_FINITE)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("std::isinf(0.)" "${CXXHEADERS}" HAVE_PROTOTYPE_STD__ISINF)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("std::isnan(0.)" "${CXXHEADERS}" HAVE_PROTOTYPE_STD__ISNAN)
   CHECK_FUNCTIONWITHHEADER_EXISTS(flock "${HEADERS}" HAVE_PROTOTYPE_FLOCK)
   CHECK_FUNCTIONWITHHEADER_EXISTS(gethostbyname_r "${HEADERS}" HAVE_PROTOTYPE_GETHOSTBYNAME_R)
   CHECK_FUNCTIONWITHHEADER_EXISTS(gethostbyaddr_r "${HEADERS}" HAVE_PROTOTYPE_GETHOSTBYADDR_R)
@@ -602,14 +560,10 @@ endif()
 # not be defined in the standard C++ headers.
   CHECK_FUNCTIONWITHHEADER_EXISTS(_vsnprintf_s "${HEADERS}" HAVE__VSNPRINTF_S)
   CHECK_FUNCTIONWITHHEADER_EXISTS(vfprintf_s "${HEADERS}" HAVE_VFPRINTF_S)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(vsnprintf "${HEADERS}" HAVE_VSNPRINTF)
   CHECK_FUNCTIONWITHHEADER_EXISTS(vsprintf_s "${HEADERS}" HAVE_VSPRINTF_S)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(std::vfprintf "${CXXHEADERS}" HAVE_PROTOTYPE_STD__VFPRINTF)
   CHECK_FUNCTIONWITHHEADER_EXISTS(std::vsnprintf "${CXXHEADERS}" HAVE_PROTOTYPE_STD__VSNPRINTF)
   CHECK_FUNCTIONWITHHEADER_EXISTS(_stricmp "${HEADERS}" HAVE_PROTOTYPE__STRICMP)
   CHECK_FUNCTIONWITHHEADER_EXISTS(gettimeofday "${HEADERS}" HAVE_PROTOTYPE_GETTIMEOFDAY)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(mkstemp "${HEADERS}" HAVE_PROTOTYPE_MKSTEMP)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(mktemp "${HEADERS}" HAVE_PROTOTYPE_MKTEMP)
   CHECK_FUNCTIONWITHHEADER_EXISTS(strcasecmp "${HEADERS}" HAVE_PROTOTYPE_STRCASECMP)
   CHECK_FUNCTIONWITHHEADER_EXISTS(strncasecmp "${HEADERS}" HAVE_PROTOTYPE_STRNCASECMP)
   CHECK_FUNCTIONWITHHEADER_EXISTS(strerror_r "${HEADERS}" HAVE_PROTOTYPE_STRERROR_R)
@@ -619,24 +573,16 @@ endif()
   CHECK_FUNCTIONWITHHEADER_EXISTS("__sync_sub_and_fetch((int*)0,0)" "${HEADERS}" HAVE_SYNC_SUB_AND_FETCH)
   CHECK_FUNCTIONWITHHEADER_EXISTS("InterlockedIncrement((long*)0)" "${HEADERS}" HAVE_INTERLOCKED_INCREMENT)
   CHECK_FUNCTIONWITHHEADER_EXISTS("InterlockedDecrement((long*)0)" "${HEADERS}" HAVE_INTERLOCKED_DECREMENT)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("_fpclassf(0.0f)" "${HEADERS}" HAVE_PROTOTYPE__FPCLASSF)
   CHECK_FUNCTIONWITHHEADER_EXISTS("getgrnam_r((char*)0,(group*)0,(char*)0,0,(group**)0)" "${HEADERS}" HAVE_GETGRNAM_R)
   CHECK_FUNCTIONWITHHEADER_EXISTS("getpwnam_r((char*)0,(passwd*)0,(char*)0,0,(passwd**)0)" "${HEADERS}" HAVE_GETPWNAM_R)
   CHECK_FUNCTIONWITHHEADER_EXISTS("readdir_r((DIR*)0,(dirent*)0,(dirent**)0)" "${HEADERS}" HAVE_READDIR_R)
   CHECK_FUNCTIONWITHHEADER_EXISTS("readdir_r((DIR*)0,(dirent*)0)" "${HEADERS}" HAVE_OLD_READDIR_R)
-  CHECK_FUNCTIONWITHHEADER_EXISTS(nanosleep "${HEADERS}" HAVE_PROTOTYPE_NANOSLEEP)
   CHECK_FUNCTIONWITHHEADER_EXISTS("&passwd::pw_gecos" "${HEADERS}" HAVE_PASSWD_GECOS)
   CHECK_FUNCTIONWITHHEADER_EXISTS("TryAcquireSRWLockShared((PSRWLOCK)0)" "${HEADERS}" HAVE_PROTOTYPE_TRYACQUIRESRWLOCKSHARED)
-  # "definition" is an (exchangeable) identifier that is needed for successful compile test
-  CHECK_FUNCTIONWITHHEADER_EXISTS("fp_except_t definition" "${HEADERS}" HAVE_DECLARATION_FP_EXCEPT_T)
 
   # Check for some type definitions needed by JasPer and defines them if necessary
   # Even if not functions but types are looked for, the script works fine.
   # "definition" is an (exchangeable) identifier that is needed for successful compile test
-  CHECK_FUNCTIONWITHHEADER_EXISTS("uchar definition" "${HEADERS}" HAVE_UCHAR_TYPEDEF)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("ushort definition" "${HEADERS}" HAVE_USHORT_TYPEDEF)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("uint definition" "${HEADERS}" HAVE_UINT_TYPEDEF)
-  CHECK_FUNCTIONWITHHEADER_EXISTS("ulong definition" "${HEADERS}" HAVE_ULONG_TYPEDEF)
   CHECK_FUNCTIONWITHHEADER_EXISTS("long long definition" "${HEADERS}" HAVE_LONG_LONG)
   CHECK_FUNCTIONWITHHEADER_EXISTS("unsigned long long definition" "${HEADERS}" HAVE_UNSIGNED_LONG_LONG)
   CHECK_FUNCTIONWITHHEADER_EXISTS("int64_t definition" "${HEADERS}" HAVE_INT64_T)
@@ -655,9 +601,6 @@ endif()
   CHECK_FUNCTIONWITHHEADER_EXISTS("popen" "${HEADERS}" HAVE_POPEN)
   CHECK_FUNCTIONWITHHEADER_EXISTS("pclose" "${HEADERS}" HAVE_PCLOSE)
 
-  # Signal handling functions
-  CHECK_FUNCTIONWITHHEADER_EXISTS("sigjmp_buf definition" "setjmp.h" HAVE_SIGJMP_BUF)
-
 if(HAVE_LOCKF AND ANDROID)
   # When Android introduced lockf, they forgot to put the constants like F_LOCK in the
   # appropriate headers, this tests if they are defined and disables lockf if they are not
@@ -704,7 +647,7 @@ else()
 
 #include <pthread.h>
 
-int main ()
+int main()
 {
   pthread_t p;
   unsigned long l = p;
@@ -963,49 +906,6 @@ endfunction()
 
 DCMTK_CHECK_ENABLE_LFS()
 
-if(WIN32)
-  # If someone can tell me how to convince TRY_COMPILE to link against winsock,
-  # we could use tests for these. Until then, here is what would be the result:
-  set(HAVE_INTP_ACCEPT 1 CACHE INTERNAL "Set if socket functions accept an int* argument")
-  set(HAVE_INTP_GETSOCKOPT 1 CACHE INTERNAL "Set if socket functions accept an int* argument")
-else()
-  # Check if socket functions accept an int*
-  DCMTK_TRY_COMPILE(HAVE_INTP_SOCKET, "socket functions accept an int* argument"
-      "
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-#ifdef _WIN32
-/* Windows is pure evil */
-#include <windows.h>
-#else
-#include <sys/socket.h>
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-int main()
-{
-    int i;
-    struct sockaddr *addr = 0;
-    int addrlen = 0;
-    int optlen = 0;
-
-    i = accept(1, addr, &addrlen);
-    i = getsockopt(0, 0, 0, 0, &optlen);
-
-    return 0;
-}")
-  if(HAVE_INTP_SOCKET)
-    set(HAVE_INTP_ACCEPT 1 CACHE INTERNAL "Set if socket functions accept an int* argument")
-    set(HAVE_INTP_GETSOCKOPT 1 CACHE INTERNAL "Set if socket functions accept an int* argument")
-  else()
-    set(HAVE_INTP_ACCEPT 0 CACHE INTERNAL "Set if socket functions accept an int* argument")
-    set(HAVE_INTP_GETSOCKOPT 0 CACHE INTERNAL "Set if socket functions accept an int* argument")
-  endif()
-endif()
-
 # Check for alignment query / specifier support
 DCMTK_TRY_COMPILE(HAVE_GNU_ALIGNOF "__alignof__ is supported"
     "int main()
@@ -1063,32 +963,6 @@ int main()
     return enable<sizeof(sfinae<test>(0)) == sizeof(yes_type)>::result;
 }")
 
-DCMTK_TRY_COMPILE(HAVE_STD_NAMESPACE "ANSI standard C++ includes use std namespace"
-    "#include <iostream>
-int main()
-{
-    using namespace std;
-    std::cout << endl;
-    return 0;
-}")
-
-DCMTK_TRY_COMPILE(HAVE_STD__NOTHROW "the compiler supports std::nothrow"
-    "#include <new>
-int main()
-{
-    int* i = new (std::nothrow) int;
-    return 0;
-}")
-
-DCMTK_TRY_COMPILE(HAVE_NOTHROW_DELETE "the compiler supports operator delete (std::nothrow)"
-    "#include <new>
-int main()
-{
-    int* i = 0;
-    operator delete (i,std::nothrow);
-    return 0;
-}")
-
 DCMTK_TRY_COMPILE(HAVE_STATIC_ASSERT "the compiler supports static_assert"
     "#include <cassert>
 int main()
@@ -1327,7 +1201,7 @@ endfunction()
 set(FORCE_MSVC_CPLUSPLUS_MACRO "")
 if(MSVC)
   if(NOT (MSVC_VERSION LESS 1910)) # VS 2017 and above
-    set (FORCE_MSVC_CPLUSPLUS_MACRO "/Zc:__cplusplus")
+    set(FORCE_MSVC_CPLUSPLUS_MACRO "/Zc:__cplusplus")
   endif()
 endif()
 
@@ -1358,6 +1232,12 @@ if(MSVC)
   endforeach()
 endif()
 
+if(NOT HAVE_CXX11 AND NOT DCMTK_PERMIT_CXX98)
+  # Since the situation where the user has explicitly requested CMAKE_CXX_STANDARD=98
+  # has already been handled in dcmtkPrepare.cmake, we are apparently using a compiler
+  # that uses C++98 by default, and the user has not requested anything specific.
+  message(FATAL_ERROR "DCMTK will require C++11 or later in the future (which is apparently not supported by this compiler). Use cmake option -DDCMTK_PERMIT_CXX98=ON to override this error (for now).")
+endif()
 
 if(CMAKE_CROSSCOMPILING)
   set(DCMTK_CROSS_COMPILING ${CMAKE_CROSSCOMPILING})
index bd354693055bf0e971c8e68e5d45f946de4542c0..4ba68453b3c20acdf6598c0fd7839c82ffab7ae1 100644 (file)
@@ -13,6 +13,9 @@ function(DCMTK_ADD_TESTS MODULE)
                 string(REPLACE "\\" "\\\\" TEST_COMMAND "${TEST_COMMAND}")
             elseif(ANDROID)
                 set(TEST_COMMAND "${ANDROID_TEMPORARY_FILES_LOCATION}/${MODULE}_tests")
+                set(MODULE_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${MODULE}_tests${CMAKE_EXECUTABLE_SUFFIX}")
+                list(APPEND DCMTK_TEST_EXECUTABLE_PATH "${MODULE_PATH}")
+                set(DCMTK_TEST_EXECUTABLE_PATH ${DCMTK_TEST_EXECUTABLE_PATH} CACHE INTERNAL "")
             else()
                 # not reachable, handled by not defining DCMTK_RUN_CTEST_SCRIPT
             endif()
index cfcfa443f327bd679a9881d92c8cedca8c6c21c2..973a6ea61d96e86d873685bd5109beec459dbb57 100644 (file)
@@ -47,15 +47,15 @@ endif()
 
 # Basic version information
 set(DCMTK_MAJOR_VERSION 3)
-set(DCMTK_MINOR_VERSION 6)
-set(DCMTK_BUILD_VERSION 9)
+set(DCMTK_MINOR_VERSION 7)
+set(DCMTK_BUILD_VERSION 0)
 # The ABI is not guaranteed to be stable between different snapshots/releases,
 # so this particular version number is increased for each snapshot or release.
-set(DCMTK_ABI_VERSION 19)
+set(DCMTK_ABI_VERSION 20)
 
 # Package "release" settings (some are currently unused and, therefore, disabled)
 set(DCMTK_PACKAGE_NAME "dcmtk")
-set(DCMTK_PACKAGE_DATE "2024-12-11")
+set(DCMTK_PACKAGE_DATE "2025-12-15")
 set(DCMTK_PACKAGE_VERSION "${DCMTK_MAJOR_VERSION}.${DCMTK_MINOR_VERSION}.${DCMTK_BUILD_VERSION}")
 set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_MAJOR_VERSION}${DCMTK_MINOR_VERSION}${DCMTK_BUILD_VERSION})
 set(DCMTK_PACKAGE_VERSION_SUFFIX "")
@@ -67,7 +67,7 @@ set(DCMTK_PACKAGE_VERSION_SUFFIX "")
 option(DCMTK_LINK_STATIC "Statically link all libraries and tools with the runtime and third party libraries." OFF)
 # Modify linker flags and libraries for static builds if enabled by the user
 if(DCMTK_LINK_STATIC)
-    if (NOT APPLE)
+    if(NOT APPLE)
         # MacOS does not support static libraries. DCMTK_LINK_STATIC is still useful on
         # macOS though, since it will create binaries that only depend on macOS's libc.
         set(CMAKE_EXE_LINKER_FLAGS "-static")
@@ -95,14 +95,14 @@ endif()
 
 option(DCMTK_PORTABLE_LINUX_BINARIES "Create ELF binaries while statically linking all third party libraries and libstdc++." OFF)
 if(DCMTK_PORTABLE_LINUX_BINARIES)
-    if (DCMTK_LINK_STATIC)
+    if(DCMTK_LINK_STATIC)
         message(FATAL_ERROR "Options DCMTK_LINK_STATIC and DCMTK_PORTABLE_LINUX_BINARIES are mutually exclusive.")
     endif()
     # only use static versions of third party libraries
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
 
     # When using gcc and clang, use the static version of libgcc/libstdc++.
-    if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
+    if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
         (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR
         (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") OR
         (CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang") OR
@@ -128,10 +128,19 @@ endfunction()
 # This should possibly be enhanced by using find_package() at some point. The best solution
 # would probably be to compile all third-party libraries ourself.
 if(DCMTK_LINK_STATIC OR DCMTK_PORTABLE_LINUX_BINARIES)
+    get_static_library("STATIC_ZLIB" "libz.a")
+    set(LIBPNG_EXTRA_LIBS_STATIC "${STATIC_ZLIB}")
     get_static_library("STATIC_DL" "libdl.a")
     get_static_library("STATIC_LZMA" "liblzma.a")
-    get_static_library("STATIC_ZLIB" "libz.a")
-    set(LIBXML2_EXTRA_LIBS_STATIC "${STATIC_LZMA}" "${STATIC_ZLIB}" "${STATIC_DL}")
+
+    # On Debian Linux, libxml2 depends on libicu. We do not want that dependency in our
+    # own builds since it massively increases the size of the executable binaries.
+    # If you still want to try, then enable the following two statements:
+    #
+    # get_static_library("STATIC_ICUUC" "libicuuc.a")
+    # get_static_library("STATIC_ICUDATA" "libicudata.a")
+
+    set(LIBXML2_EXTRA_LIBS_STATIC "${STATIC_LZMA}" "${STATIC_ZLIB}" "${STATIC_DL}" "${STATIC_ICUUC}" "${STATIC_ICUDATA}")
     get_static_library("STATIC_PTHREAD" "libpthread.a")
     set(OPENJPEG_EXTRA_LIBS_STATIC "${STATIC_PTHREAD}")
     set(OPENSSL_EXTRA_LIBS_STATIC "${STATIC_DL}")
@@ -146,10 +155,17 @@ if(DCMTK_LINK_STATIC OR DCMTK_PORTABLE_LINUX_BINARIES)
     get_static_library("STATIC_JBIG" "libjbig.a")
     get_static_library("STATIC_JPEG" "libjpeg.a")
     get_static_library("STATIC_DEFLATE" "libdeflate.a")
-    set(TIFF_EXTRA_LIBS_STATIC "${STATIC_WEBP}" "${STATIC_ZSTD}" "${STATIC_LZMA}" "${STATIC_JBIG}" "${STATIC_JBIG}" "${STATIC_DEFLATE}" "${STATIC_ZLIB}")
+
+    # On Debian Linux, libtiff depends on libLerc. We do not need that dependency in our
+    # own builds. If want to use Debian's libtiff, then enable the following statement:
+    #
+    # get_static_library("STATIC_LIBLERC" "libLerc.a")
+
+    set(TIFF_EXTRA_LIBS_STATIC "${STATIC_WEBP}" "${STATIC_ZSTD}" "${STATIC_LZMA}" "${STATIC_JBIG}" "${STATIC_JBIG}" "${STATIC_DEFLATE}" "${STATIC_ZLIB}" "${STATIC_LIBLERC}")
     get_static_library("STATIC_NSL" "libnsl.a")
     set(WRAP_EXTRA_LIBS_STATIC "${STATIC_NSL}")
 else()
+    set(LIBPNG_EXTRA_LIBS_STATIC)
     set(LIBXML2_EXTRA_LIBS_STATIC)
     set(OPENJPEG_EXTRA_LIBS_STATIC)
     set(OPENSSL_EXTRA_LIBS_STATIC)
@@ -177,7 +193,7 @@ option(DCMTK_WITH_PNG "Configure DCMTK with support for PNG." ON)
 option(DCMTK_WITH_XML "Configure DCMTK with support for XML." ON)
 option(DCMTK_WITH_ZLIB "Configure DCMTK with support for ZLIB." ON)
 option(DCMTK_WITH_OPENSSL "Configure DCMTK with support for OPENSSL." ON)
-option(DCMTK_WITH_SNDFILE "Configure DCMTK with support for SNDFILE." ON)
+option(DCMTK_WITH_SNDFILE "Configure DCMTK with support for SNDFILE." OFF)
 option(DCMTK_WITH_ICONV "Configure DCMTK with support for ICONV." ON)
 if(NOT WIN32)
   option(DCMTK_WITH_WRAP "Configure DCMTK with support for WRAP." ON)
@@ -224,7 +240,7 @@ else()
 endif()
 set(DCMTK_DEFAULT_DICT "${DCMTK_DEFAULT_DICT_DEFAULT}" CACHE STRING "Denotes whether DCMTK will use built-in (compiled-in), external (file), or no default dictionary on startup")
 set_property(CACHE DCMTK_DEFAULT_DICT PROPERTY STRINGS builtin external none)
-if (DCMTK_DEFAULT_DICT EQUAL "none")
+if(DCMTK_DEFAULT_DICT EQUAL "none")
   message(WARNING "Denotes whether DCMTK will use built-in (compiled-in), external (file), or no default dictionary on startup")
 endif()
 
@@ -234,14 +250,14 @@ option(DCMTK_USE_DCMDICTPATH "Enable reading dictionary that is defined through
 
 # Declare the option DCMTK_ENABLE_BUILTIN_OFICONV_DATA, which by default is ON when
 # we are compiling shared libraries.
-if (BUILD_SHARED_LIBS)
+if(BUILD_SHARED_LIBS)
   option(DCMTK_ENABLE_BUILTIN_OFICONV_DATA "Embed oficonv data files into oficonv library" ON)
 else()
   option(DCMTK_ENABLE_BUILTIN_OFICONV_DATA "Embed oficonv data files into oficonv library" OFF)
 endif()
 
 # evaluate the option DCMTK_ENABLE_BUILTIN_OFICONV_DATA
-if (DCMTK_ENABLE_BUILTIN_OFICONV_DATA)
+if(DCMTK_ENABLE_BUILTIN_OFICONV_DATA)
   add_definitions(-DDCMTK_ENABLE_BUILTIN_OFICONV_DATA)
 endif()
 
@@ -370,7 +386,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 if(WIN32)
   option(DCMTK_OVERWRITE_WIN32_COMPILER_FLAGS  "Modify the default compiler flags selected by CMake." ON)
   option(DCMTK_COMPILE_WIN32_MULTITHREADED_DLL "Compile DCMTK using the Multithreaded DLL runtime library." OFF)
-  if (BUILD_SHARED_LIBS)
+  if(BUILD_SHARED_LIBS)
     set(DCMTK_COMPILE_WIN32_MULTITHREADED_DLL ON)
   endif()
 else()
@@ -380,7 +396,7 @@ else()
 endif()
 
 if(WIN32 AND CMAKE_GENERATOR MATCHES "Visual Studio .*|NMake .*")
-  if (POLICY CMP0091)
+  if(POLICY CMP0091)
     # CMake 3.15 and newer use CMAKE_MSVC_RUNTIME_LIBRARY to select
     # the MSVC runtime library
     if(DCMTK_COMPILE_WIN32_MULTITHREADED_DLL OR BUILD_SHARED_LIBS)
@@ -527,7 +543,7 @@ else()   # ... for non-Windows systems
   endif()
 
   # When compiling with IBM xlC, add flags to suppress some noisy C++ warnings
-  if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "XL")
+  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "XL")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qsuppress=1500-029:1500-030")
   endif()
 
@@ -551,28 +567,34 @@ endif()
 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
 
+option(DCMTK_PERMIT_CXX98 "Permit (deprecated) compilation with C++98 language standard. This will cease to function in a future DCMTK release." OFF)
+
 # If desired C++ standard is at least C++11, set DCMTK_MODERN_CXX_STANDARD to true
 # and remember it in global property DCMTK_MODERN_CXX_STANDARD.
 # This is later evaluated in GenerateDCMTKConfigure.cmake in order to check
 # whether the compiler actually supports the required C++ standards up to the
 # version specified in CMAKE_CXX_STANDARD. Finally, the highest C++ version
 # (<= CMAKE_CXX_STANDARD) will be selected that the compiler actually supports.
-if (NOT DEFINED CMAKE_CXX_STANDARD)
+if(NOT DEFINED CMAKE_CXX_STANDARD)
   set(CMAKE_CXX_STANDARD 11)
   set(DCMTK_MODERN_CXX_STANDARD TRUE)
+elseif(CMAKE_CXX_STANDARD MATCHES "^9[0-9]?$" AND NOT DCMTK_PERMIT_CXX98)
+  message(FATAL_ERROR "DCMTK will require C++11 or later in the future. Use cmake option -DDCMTK_PERMIT_CXX98=ON to override this error (for now)")
 elseif(CMAKE_CXX_STANDARD MATCHES "^9[0-9]?$")
   set(DCMTK_MODERN_CXX_STANDARD FALSE)
-  message(WARNING "DCMTK will require C++11 or later in the future.")
+  message(WARNING "DCMTK will require C++11 or later in the future, continuing for now.")
 elseif(CMAKE_CXX_STANDARD GREATER 20)
   MESSAGE(WARNING "DCMTK is only known to compile for C++ versions <= 20 (C++${CMAKE_CXX_STANDARD} requested).")
   set(DCMTK_MODERN_CXX_STANDARD TRUE)
 else() # CMAKE_CXX_STANDARD is 11, 14, 17 or 20
   set(DCMTK_MODERN_CXX_STANDARD TRUE)
 endif()
+
 define_property(GLOBAL PROPERTY DCMTK_MODERN_CXX_STANDARD
   BRIEF_DOCS "TRUE when compiling C++11 (or newer) code."
   FULL_DOCS "TRUE when the compiler does support and is configured for C++11 or a later C++ standard."
 )
+
 # Remember globally that we use at least C++11
 set_property(GLOBAL PROPERTY DCMTK_MODERN_CXX_STANDARD ${DCMTK_MODERN_CXX_STANDARD})
 # Build global list of all modern C++ standard versions supported so far
@@ -597,12 +619,12 @@ if(MSVC)
     add_compile_options("/W4")
 else()
     # Add -Wall to the compiler flags if we are compiling with gcc or Clang.
-    if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
-        (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR
-        (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") OR
-        (CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang") OR
-        (CMAKE_CXX_COMPILER_ID STREQUAL "XLClang"))
-        add_compile_options("-Wall")
+    if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
+       (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR
+       (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") OR
+       (CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang") OR
+       (CMAKE_CXX_COMPILER_ID STREQUAL "XLClang"))
+       add_compile_options("-Wall")
     endif()
 endif()
 
@@ -720,8 +742,10 @@ function(DCMTK_TEST_SOCKET_LIBRARY NAME SYMBOL)
   endif()
 endfunction()
 
-DCMTK_TEST_SOCKET_LIBRARY(nsl "gethostbyname")
-DCMTK_TEST_SOCKET_LIBRARY(socket "socket")
+if(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_VERSION VERSION_LESS "11.4")
+  DCMTK_TEST_SOCKET_LIBRARY(nsl "gethostbyname")
+  DCMTK_TEST_SOCKET_LIBRARY(socket "socket")
+endif()
 
 #-----------------------------------------------------------------------------
 # Test if SunPro compiler and add features
index 17232d687b37e64c2c1af5384399c3731e564193..6a1cc92e1ea91dae5978524ba4f413885b49b34e 100644 (file)
 #       * STOPPED  - the emulated device has been
 #                    shutdown or is currently being
 #                    shutdown
-#  EMULATOR_UUID: a generated ID to identify the emulator
-#    instance. Meant to prevent accessing the wrong device
-#    in case multiple Android devices are accessible.
 #  EMULATOR_NAME: the name of the emulator instance.
 #    all running emulator instances are named by the SDK
-#    in a locally unique fashion. The name will only be
-#    available in case the state is 'RUNNING', since
-#    only the name of running devices can be retrieved
-#    by UUID matching.
+#    in a locally unique fashion from the provided port.
 #    An emulator instance is accessed by the different
 #    tools of the NDK (e. g. 'adb') by referring to the
 #    instance with the value of EMULATOR_NAME.
@@ -42,23 +36,19 @@ include(CMakeParseArguments)
 # individual components.
 # VAR - the emulator instance handle object to unpack
 # EMULATOR_STATE - will contain the emulators state
-# EMULATOR_UUID  - will contain the generated UUID that
-#                  identifies the emulator instance
 # EMULATOR_NAME  - will contain the instance name, required
 #                  to access the emulator via 'adb' etc.
-# All three outputs will be unset if the object in VAR
+# All two outputs will be unset if the object in VAR
 # is not a valid emulator instance handle.
 # All additional arguments will be ignored.
 #
 macro(DCMTK_ANDROID_GET_OBJECT_PROPERTIES VAR)
     list(LENGTH ${VAR} ${VAR}_LENGTH)
-    if(${VAR}_LENGTH EQUAL 3)
+    if(${VAR}_LENGTH EQUAL 2)
         list(GET ${VAR} 0 EMULATOR_STATE)
-        list(GET ${VAR} 1 EMULATOR_UUID)
-        list(GET ${VAR} 2 EMULATOR_NAME)
+        list(GET ${VAR} 1 EMULATOR_NAME)
     else()
         unset(EMULATOR_STATE)
-        unset(EMULATOR_UUID)
         unset(EMULATOR_NAME)
     endif()
 endmacro()
@@ -69,12 +59,11 @@ endmacro()
 # VAR - the name of the variable that shall contain the
 #       resulting instance handle object.
 # EMULATOR_STATE - the state to set
-# EMULATOR_UUID  - the UUID to set
 # EMULATOR_NAME  - the name to set
 # All additional arguments will be ignored.
 #
-macro(DCMTK_ANDROID_SET_OBJECT_PROPERTIES VAR EMULATOR_STATE EMULATOR_UUID EMULATOR_NAME)
-    set(${VAR} "${EMULATOR_STATE}" "${EMULATOR_UUID}" "${EMULATOR_NAME}" CACHE INTERNAL "")
+macro(DCMTK_ANDROID_SET_OBJECT_PROPERTIES VAR EMULATOR_STATE EMULATOR_NAME)
+    set(${VAR} "${EMULATOR_STATE}" "${EMULATOR_NAME}" CACHE INTERNAL "")
 endmacro()
 
 #
@@ -117,7 +106,7 @@ endfunction()
 #
 function(DCMTK_SETUP_ANDROID_EMULATOR)
     if(NOT ANDROID_TEMPORARY_FILES_LOCATION)
-        set(ANDROID_TEMPORARY_FILES_LOCATION "/cache" CACHE STRING "The path on the Android device that should be used for temporary files")
+        set(ANDROID_TEMPORARY_FILES_LOCATION "/data/local/cache" CACHE STRING "The path on the Android device that should be used for temporary files")
     endif()
     if(NOT ANDROID_SDK_ROOT)
         if(CMAKE_HOST_SYSTEM MATCHES "Windows.*")
@@ -127,20 +116,20 @@ function(DCMTK_SETUP_ANDROID_EMULATOR)
             set(ANDROID_SDK_ROOT "/opt/android-sdk" CACHE PATH "Location of the Android SDK")
         endif()
     endif()
-    find_program(ANDROID_EMULATOR_PROGRAM emulator PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES tools NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+    find_program(ANDROID_EMULATOR_PROGRAM emulator PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES emulator NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
     if(CMAKE_HOST_SYSTEM MATCHES "Windows.*")
-        find_program(ANDROID_ANDROID_PROGRAM android.bat PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES tools NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+        find_program(ANDROID_AVDMANAGER_PROGRAM avdmanager PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES tools NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
     else()
-        find_program(ANDROID_ANDROID_PROGRAM android PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES tools NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+      find_program(ANDROID_AVDMANAGER_PROGRAM avdmanager PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES cmdline-tools/latest/bin NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
     endif()
     find_program(ANDROID_ADB_PROGRAM adb PATHS ${ANDROID_SDK_ROOT} PATH_SUFFIXES platform-tools NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
-    if(NOT ANDROID_EMULATOR_PROGRAM OR NOT ANDROID_ANDROID_PROGRAM OR NOT ANDROID_ADB_PROGRAM)
+    if(NOT ANDROID_EMULATOR_PROGRAM OR NOT ANDROID_AVDMANAGER_PROGRAM OR NOT ANDROID_ADB_PROGRAM)
         message(FATAL_ERROR
             "Failed to detect the Android SDK, please set ANDROID_SDK_ROOT to the location of your Android SDK"
             "or set the missing tools manually!"
         )
     else()
-        execute_process(COMMAND "${ANDROID_ANDROID_PROGRAM}" list avd RESULT_VARIABLE RESULT OUTPUT_VARIABLE OUTPUT ERROR_QUIET)
+        execute_process(COMMAND "${ANDROID_AVDMANAGER_PROGRAM}" list avd RESULT_VARIABLE RESULT OUTPUT_VARIABLE OUTPUT ERROR_QUIET)
         string(REGEX MATCHALL "Name:[ \t]*[^\r\n]*" ANDROID_AVAILABLE_AVDS ${OUTPUT})
         string(REGEX REPLACE "Name:[ \t]*([^\r\n;]*)" "\\1" ANDROID_AVAILABLE_AVDS "${ANDROID_AVAILABLE_AVDS}")
         set(ANDROID_EMULATOR_AVD "${ANDROID_EMULATOR_AVD}" CACHE STRING "Android emulator Android Virtual Device (AVD) configuration" FORCE)
@@ -190,60 +179,52 @@ function(DCMTK_ANDROID_LIST_EMULATORS ONLINE OFFLINE)
 endfunction()
 
 #
-# Generate a random ID that is hopefully unique
-# enough to be used as the instance UUID.
+# Generate the emulator name from the provided port.
+# Since the port decides the name of the emulator
+# anyway, this is just to check if the emulator really
+# exists under the expected name.
 # VAR - the name of the variable that will receive
-#       the generated UUID as a string value
+#       the generated name as a string value
 # Will ignore all additional arguments.
 #
-function(DCMTK_ANDROID_EMULATOR_GENERATE_UUID VAR)
-    string(RANDOM LENGTH 20 RAND)
-    string(TIMESTAMP TM)
-    set(${VAR} "${TM}${RAND}")
-    string(MD5 ${VAR} ${${VAR}})
+function(DCMTK_ANDROID_EMULATOR_GENERATE_NAME_FROM_PORT VAR)
+    set(${VAR} "emulator-${ANDROID_EMULATOR_PORT}")
     set(${VAR} ${${VAR}} PARENT_SCOPE)
 endfunction()
 
 #
-# Tries to query the UUID property of an accessible Android device.
+# Tries to query the emulator name of an accessible Android device.
 # EMULATOR_NAME - the device name, as returned by DCMTK_ANDROID_LIST_EMULATORS
-# VAR           - the name of the variable that will be set to the device UUID
+# VAR           - the name of the variable that will be set to the emulator name
 # Will unset the variable referred to by VAR if no device with the given name
 # is accessible or the device is offline.
 # Will ignore all additional arguments.
 #
-function(DCMTK_ANDROID_GET_EMULATOR_UUID EMULATOR_NAME VAR)
-    execute_process(
-        COMMAND "${ANDROID_ADB_PROGRAM}" -s "${EMULATOR_NAME}" shell getprop "ro.emu.uuid"
-        RESULT_VARIABLE RESULT
-        OUTPUT_VARIABLE OUTPUT
-        ERROR_QUIET
-    )
+function(DCMTK_ANDROID_GET_EMULATOR_NAME_FROM_PORT EMULATOR_NAME VAR)
     DCMTK_UNSET_PARENT_SCOPE(${VAR})
-    if(NOT RESULT)
-        string(STRIP "${OUTPUT}" UUID)
-        if(UUID)
-            set("${VAR}" ${UUID} PARENT_SCOPE)
-        endif()
+    if(ANDROID_EMULATOR_PORT)
+        set(EMULATOR_NAME "emulator-${ANDROID_EMULATOR_PORT}" PARENT_SCOPE)
     endif()
 endfunction()
 
 #
 # Retrieves the name of the emulator instance referred to by
-# the given UUID. Will wait until the device becomes online
+# the given port. Will wait until the device becomes online
 # to query the name.
 # VAR           - the name of the variable that will be set
 #                 to the device name
-# EMULATOR_UUID - the emulator UUID of the device to inquired
+# EMULATOR_NAME_FROM_PORT - the emulator name of the device to inquired
 # Will wait until all available devices are online or the right
 # one has been found.
 # Will ignore all additional arguments.
 #
-function(DCMTK_ANDROID_GET_EMULATOR_NAME VAR EMULATOR_UUID)
+function(DCMTK_ANDROID_GET_EMULATOR_NAME VAR EMULATOR_NAME_FROM_PORT)
     DCMTK_ANDROID_LIST_EMULATORS(ONLINE_EMULATORS OFFLINE_EMULATORS)
     foreach(EMULATOR ${ONLINE_EMULATORS})
-        DCMTK_ANDROID_GET_EMULATOR_UUID("${EMULATOR}" UUID)
-        if(EMULATOR_UUID STREQUAL UUID)
+        DCMTK_ANDROID_GET_EMULATOR_NAME_FROM_PORT("${EMULATOR}" ANDROID_EMULATOR_PORT)
+        # The emulator could have a different name in another language, but the port should always
+        # be the same.
+        if(EMULATOR_NAME MATCHES ".*-${ANDROID_EMULATOR_PORT}")
             set("${VAR}" "${EMULATOR}" PARENT_SCOPE)
             return()
         endif()
@@ -259,9 +240,8 @@ function(DCMTK_ANDROID_GET_EMULATOR_NAME VAR EMULATOR_UUID)
             ERROR_QUIET
         )
         if(NOT RESULT)
-            DCMTK_ANDROID_GET_EMULATOR_UUID("${EMULATOR}" UUID)
-            if(UUID)
-                if(EMULATOR_UUID STREQUAL UUID)
+            if(ANDROID_EMULATOR_PORT)
+                if(EMULATOR_NAME STREQUAL "emulator-${ANDROID_EMULATOR_PORT}")
                     set("${VAR}" "${EMULATOR}" PARENT_SCOPE)
                     return()
                 endif()
@@ -287,36 +267,41 @@ endfunction()
 #
 function(DCMTK_ANDROID_START_EMULATOR VAR)
     DCMTK_SETUP_ANDROID_EMULATOR()
+    if(NOT ANDROID_EMULATOR_PORT)
+        message(FATAL_ERROR "Please provide the port the Android emulator should use. The range is 5554 to 5682 and the port should be an even number.")
+    else()
+      set(ANDROID_EMULATOR_PORT ${ANDROID_EMULATOR_PORT} CACHE INTERNAL "")
+    endif()
     if(NOT ANDROID_EMULATOR_AVD)
         message(FATAL_ERROR "Please select which Android emulator Android Virtual Device (AVD) configuration to use!")
     else()
         DCMTK_ANDROID_GET_OBJECT_PROPERTIES("${VAR}")
         if(NOT EMULATOR_STATE)
-            DCMTK_ANDROID_EMULATOR_GENERATE_UUID(EMULATOR_UUID)
+            DCMTK_ANDROID_EMULATOR_GENERATE_NAME_FROM_PORT(EMULATOR_NAME_FROM_PORT)
         elseif(EMULATOR_STATE STREQUAL "RUNNING")
-            DCMTK_ANDROID_GET_EMULATOR_UUID("${EMULATOR_NAME}" UUID)
+            DCMTK_ANDROID_GET_EMULATOR_NAME_FROM_PORT("${EMULATOR_NAME}" EMULATOR_NAME_FROM_PORT)
             # Do nothing if the running emulator instance is ok and can be reused.
             # Otherwise restart it.
-            if(UUID STREQUAL EMULATOR_UUID)
+            if(EMULATOR_NAME_FROM_PORT STREQUAL EMULATOR_NAME)
                 message(STATUS "Reusing already running Android device emulator...")
                 return()
             endif()
         elseif(EMULATOR_STATE STREQUAL "STARTING")
             # Is it really starting, or has somebody aborted it?
             message(STATUS "Found previously started Android device emulator, checking if it's still present...")
-            DCMTK_ANDROID_GET_EMULATOR_NAME(EMULATOR_NAME "${EMULATOR_UUID}")
+            DCMTK_ANDROID_GET_EMULATOR_NAME(EMULATOR_NAME "${EMULATOR_NAME_FROM_PORT}")
             if(EMULATOR_NAME)
               message(STATUS "Found previously started Android device emulator, checking if it's still present... yes")
-              DCMTK_ANDROID_SET_OBJECT_PROPERTIES(${VAR} RUNNING "${EMULATOR_UUID}" "${EMULATOR_NAME}")
+              DCMTK_ANDROID_SET_OBJECT_PROPERTIES(${VAR} RUNNING "${EMULATOR_NAME}")
               return()
             endif()
             message(STATUS "Found previously started Android device emulator, checking if it's still present... no")
         endif()
         message(STATUS "Starting the Android device emulator...")
         if(CMAKE_HOST_SYSTEM MATCHES "Windows.*")
-            set(COMMAND sh -c "${ANDROID_EMULATOR_PROGRAM} -avd ${ANDROID_EMULATOR_AVD} -no-boot-anim -prop ro.emu.uuid=${EMULATOR_UUID} >${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android-emulator.log 2>&1 < /dev/null &")
+            set(COMMAND sh -c "${ANDROID_EMULATOR_PROGRAM} -avd ${ANDROID_EMULATOR_AVD} -no-boot-anim -port ${ANDROID_EMULATOR_PORT} >${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android-emulator.log 2>&1 < /dev/null &")
         else()
-            set(COMMAND sh -c "${ANDROID_EMULATOR_PROGRAM} -avd ${ANDROID_EMULATOR_AVD} -no-window -no-boot-anim -prop ro.emu.uuid=${EMULATOR_UUID} >${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android-emulator.log 2>&1 < /dev/null &")
+            set(COMMAND sh -c "${ANDROID_EMULATOR_PROGRAM} -avd ${ANDROID_EMULATOR_AVD} -no-window -no-boot-anim -port ${ANDROID_EMULATOR_PORT} >${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android-emulator.log 2>&1 < /dev/null &")
         endif()
         execute_process(
             COMMAND ${COMMAND}
@@ -325,7 +310,7 @@ function(DCMTK_ANDROID_START_EMULATOR VAR)
             ERROR_QUIET
         )
         if(NOT RESULT)
-            DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" STARTING "${EMULATOR_UUID}" "")
+            DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" STARTING "${EMULATOR_NAME}")
         else()
             DCMTK_ANDROID_DESTROY_OBJECT("${VAR}")
             message(FATAL_ERROR "Error starting Android emulator.")
@@ -337,7 +322,7 @@ endfunction()
 # Restart adb/the emulated device in root mode so that we gain write access to
 # the device.
 # Newer versions of the SDK seem to require this for doing anything meaningful
-# with it.
+# with it. It also only works on emulated devices without Playstore API.
 # EMULATOR_NAME - the name of the emulated device that shall be rooted.
 # Will ignore all additional arguments.
 #
@@ -347,9 +332,8 @@ function(DCMTK_ANDROID_ADB_ROOT EMULATOR_NAME)
         OUTPUT_QUIET
         ERROR_QUIET
     )
-    # the SDK was seemingly designed by a five year old, the device will
-    # become invisible while it is being rooted, therefore, wait until
-    # it is ready again
+    # The device will become invisible while it is being rooted, therefore,
+    # wait until it is ready again.
     set(STATUS 1)
     while(STATUS)
         execute_process(
@@ -383,10 +367,10 @@ function(DCMTK_ANDROID_WAIT_FOR_EMULATOR VAR)
     else()
         message(STATUS "Waiting until the Android device emulator is ready to receive instructions...")
         while(NOT EMULATOR_NAME)
-            DCMTK_ANDROID_GET_EMULATOR_NAME(EMULATOR_NAME "${EMULATOR_UUID}")
+            DCMTK_ANDROID_GET_EMULATOR_NAME(EMULATOR_NAME "${EMULATOR_NAME_FROM_PORT}")
         endwhile()
         DCMTK_ANDROID_ADB_ROOT("${EMULATOR_NAME}")
-        DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" RUNNING "${EMULATOR_UUID}" "${EMULATOR_NAME}")
+        DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" RUNNING "${EMULATOR_NAME}")
     endif()
 endfunction()
 
@@ -453,7 +437,7 @@ function(DCMTK_ANDROID_STOP_EMULATOR VAR)
           ERROR_QUIET
         )
         if(NOT RESULT)
-            DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" STOPPED "${EMULATOR_UUID}" "")
+            DCMTK_ANDROID_SET_OBJECT_PROPERTIES("${VAR}" STOPPED "${EMULATOR_NAME}")
         else()
             message(WARNING "Unable to stop the android device emulator, please shutdown \"${EMULATOR_NAME}\" manually!")
         endif()
index a84aee0c6e59e4e0c85d4fd5024f666e0a0a4fda..6d39b4e40963448d6bebfb959eac2f95341cae3e 100644 (file)
 /* Define the environment variable path separator */
 #define ENVIRONMENT_PATH_SEPARATOR '@ENVIRONMENT_PATH_SEPARATOR@'
 
-/* Define to 1 if you have the `access' function. */
-#cmakedefine HAVE_ACCESS @HAVE_ACCESS@
-
 /* Define to 1 if you have the <alloca.h> header file. */
 #cmakedefine HAVE_ALLOCA_H @HAVE_ALLOCA_H@
 
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #cmakedefine HAVE_ARPA_INET_H @HAVE_ARPA_INET_H@
 
-/* Define to 1 if you have the `bcmp' function. */
-#cmakedefine HAVE_BCMP @HAVE_BCMP@
+/* Define to 1 if you have the <cstdint> header file. */
+#cmakedefine HAVE_CSTDINT @HAVE_CSTDINT@
 
 /* Define to 1 if you have the `cuserid' function. */
 #cmakedefine HAVE_CUSERID @HAVE_CUSERID@
@@ -80,9 +77,6 @@
 /* Define to 1 if you have the `fgetln' function. */
 #cmakedefine HAVE_FGETLN @HAVE_FGETLN@
 
-/* Define if your system has a declaration for fp_except_t in ieeefp.h */
-#cmakedefine HAVE_DECLARATION_FP_EXCEPT_T @HAVE_DECLARATION_FP_EXCEPT_T@
-
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.*/
 #cmakedefine HAVE_DIRENT_H @HAVE_DIRENT_H@
 
 /* Define to 1 if <errno.h> defined ENAMETOOLONG. */
 #cmakedefine HAVE_ENAMETOOLONG @HAVE_ENAMETOOLONG@
 
-/* Define to 1 if you have the <fcntl.h> header file. */
-#cmakedefine HAVE_FCNTL_H @HAVE_FCNTL_H@
-
-/* Define to 1 if you have the `finite' function. */
-#cmakedefine HAVE_FINITE @HAVE_FINITE@
-
 /* Define to 1 if you have the `flock' function. */
 #cmakedefine HAVE_FLOCK @HAVE_FLOCK@
 
 /* Define to 1 if you have the `getlogin_r' function. */
 #cmakedefine HAVE_GETLOGIN_R @HAVE_GETLOGIN_R@
 
-/* Define to 1 if you have the `getpid' function. */
-#cmakedefine HAVE_GETPID @HAVE_GETPID@
-
 /* Define to 1 if you have the `getpwnam' function. */
 #cmakedefine HAVE_GETPWNAM @HAVE_GETPWNAM@
 
-/* Define to 1 if you have the `getrusage' function. */
-#cmakedefine HAVE_GETRUSAGE @HAVE_GETRUSAGE@
-
 /* Define to 1 if you have the `gettimeofday' function. */
 #cmakedefine HAVE_GETTIMEOFDAY @HAVE_GETTIMEOFDAY@
 
 /* Define to 1 if you have the <ieeefp.h> header file. */
 #cmakedefine HAVE_IEEEFP_H @HAVE_IEEEFP_H@
 
-/* Define to 1 if you have the `index' function. */
-#cmakedefine HAVE_INDEX @HAVE_INDEX@
-
-/* Define if your system declares argument 3 of accept() as int * instead of
-   size_t * or socklen_t * */
-#cmakedefine HAVE_INTP_ACCEPT @HAVE_INTP_ACCEPT@
-
-/* Define if your system declares argument 5 of getsockopt() as int * instead
-   of size_t * or socklen_t */
-#cmakedefine HAVE_INTP_GETSOCKOPT @HAVE_INTP_GETSOCKOPT@
-
 /* Define to 1 if you have the <io.h> header file. */
 #cmakedefine HAVE_IO_H @HAVE_IO_H@
 
-/* Define to 1 if you have the `itoa' function. */
-#cmakedefine HAVE_ITOA @HAVE_ITOA@
-
 /* Define to 1 if you have the <langinfo.h> header file. */
 #cmakedefine HAVE_LANGINFO_H @HAVE_LANGINFO_H@
 
 /* Define to 1 if you have the <libc.h> header file. */
 #cmakedefine HAVE_LIBC_H @HAVE_LIBC_H@
 
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-#cmakedefine HAVE_LIBNSL @HAVE_LIBNSL@
-
 /* Define to 1 if the <libpng/png.h> header shall be used instead of <png.h>. */
 #cmakedefine HAVE_LIBPNG_PNG_H @HAVE_LIBPNG_PNG_H@
 
-/* Define to 1 if you have the `socket' library (-lsocket). */
-#cmakedefine HAVE_LIBSOCKET @HAVE_LIBSOCKET@
-
-/* Define to 1 if you have the `listen' function. */
-#cmakedefine HAVE_LISTEN @HAVE_LISTEN@
-
 /* Define to 1 if you have the `localtime_r' function. */
 #cmakedefine HAVE_LOCALTIME_R @HAVE_LOCALTIME_R@
 
 /* Define to 1 if you have the `malloc_debug' function. */
 #cmakedefine HAVE_MALLOC_DEBUG @HAVE_MALLOC_DEBUG@
 
-/* Define to 1 if you have the <malloc.h> header file. */
-#cmakedefine HAVE_MALLOC_H @HAVE_MALLOC_H@
-
 /* Define to 1 if you have the `mkstemp' function. */
 #cmakedefine HAVE_MKSTEMP @HAVE_MKSTEMP@
 
-/* Define to 1 if you have the `mktemp' function. */
-#cmakedefine HAVE_MKTEMP @HAVE_MKTEMP@
-
 /* Define to 1 if you have the <mqueue.h> header file. */
 #cmakedefine HAVE_MQUEUE_H @HAVE_MQUEUE_H@
 
 /* Define to 1 if you have readdir_r */
 #cmakedefine HAVE_READDIR_R @HAVE_READDIR_R@
 
-/* Define if your system has a prototype for feenableexcept in fenv.h */
-#cmakedefine HAVE_PROTOTYPE_FEENABLEEXCEPT @HAVE_PROTOTYPE_FEENABLEEXCEPT@
-
-/* Define if your system has a prototype for finite in math.h */
-#cmakedefine HAVE_PROTOTYPE_FINITE @HAVE_PROTOTYPE_FINITE@
-
 /* Define to 1 if your has a prototype for `TryAcquireSRWLockShared' in windows.h (Win32 only). */
 #cmakedefine HAVE_PROTOTYPE_TRYACQUIRESRWLOCKSHARED @HAVE_PROTOTYPE_TRYACQUIRESRWLOCKSHARED@
 
    unistd.h */
 #cmakedefine HAVE_PROTOTYPE_GETTIMEOFDAY @HAVE_PROTOTYPE_GETTIMEOFDAY@
 
-/* Define if your system has a prototype for std::isinf in cmath */
-#cmakedefine HAVE_PROTOTYPE_STD__ISINF @HAVE_PROTOTYPE_STD__ISINF@
-
-/* Define if your system has a prototype for std::isnan in cmath */
-#cmakedefine HAVE_PROTOTYPE_STD__ISNAN @HAVE_PROTOTYPE_STD__ISNAN@
-
-/* Define if your system has a prototype for fpclassf in math.h */
-#cmakedefine HAVE_PROTOTYPE__FPCLASSF @HAVE_PROTOTYPE__FPCLASSF@
-
-/* Define if your system has a prototype for mkstemp in libc.h unistd.h
-   stdlib.h */
-#cmakedefine HAVE_PROTOTYPE_MKSTEMP @HAVE_PROTOTYPE_MKSTEMP@
-
-/* Define if your system has a prototype for mktemp in libc.h unistd.h
-   stdlib.h */
-#cmakedefine HAVE_PROTOTYPE_MKTEMP @HAVE_PROTOTYPE_MKTEMP@
-
-/* Define if your system has a prototype for std::vfprintf in stdarg.h */
-#cmakedefine HAVE_PROTOTYPE_STD__VFPRINTF @HAVE_PROTOTYPE_STD__VFPRINTF@
-
 /* Define if your system has a prototype for std::vsnprintf in stdio.h */
 #cmakedefine HAVE_PROTOTYPE_STD__VSNPRINTF @HAVE_PROTOTYPE_STD__VSNPRINTF@
 
 /* Define if your system has a prototype for _stricmp in string.h */
 #cmakedefine HAVE_PROTOTYPE__STRICMP @HAVE_PROTOTYPE__STRICMP@
 
-/* Define if your system has a prototype for nanosleep in time.h */
-#cmakedefine HAVE_PROTOTYPE_NANOSLEEP @HAVE_PROTOTYPE_NANOSLEEP@
-
 /* Define to 1 if you have the <pthread.h> header file. */
 #cmakedefine HAVE_PTHREAD_H @HAVE_PTHREAD_H@
 
 /* Define to 1 if you have the <pwd.h> header file. */
 #cmakedefine HAVE_PWD_H @HAVE_PWD_H@
 
-/* Define to 1 if you have the `rindex' function. */
-#cmakedefine HAVE_RINDEX @HAVE_RINDEX@
-
 /* Define to 1 if you have the <semaphore.h> header file. */
 #cmakedefine HAVE_SEMAPHORE_H @HAVE_SEMAPHORE_H@
 
 /* Define to 1 if you have the `sleep' function. */
 #cmakedefine HAVE_SLEEP @HAVE_SLEEP@
 
-/* Define to 1 if you have the `stat' function. */
-#cmakedefine HAVE_STAT @HAVE_STAT@
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#cmakedefine HAVE_STDINT_H @HAVE_STDINT_H@
-
-/* Define to 1 if you have the C++11 <system_error> header file. */
-#cmakedefine HAVE_SYSTEM_ERROR @HAVE_SYSTEM_ERROR@
-
-/* Define to 1 if you have the <cstdint> header file. */
-#cmakedefine HAVE_CSTDINT @HAVE_CSTDINT@
-
-/* Define to 1 if you have the `strdup' function. */
-#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
-
 /* Define to 1 if `strerror_r' returns a char*. */
 #cmakedefine HAVE_CHARP_STRERROR_R @HAVE_CHARP_STRERROR_R@
 
 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.*/
 #cmakedefine HAVE_SYS_DIR_H @HAVE_SYS_DIR_H@
 
-/* Define to 1 if you have the <sys/errno.h> header file. */
-#cmakedefine HAVE_SYS_ERRNO_H @HAVE_SYS_ERRNO_H@
-
 /* Define to 1 if you have the <sys/file.h> header file. */
 #cmakedefine HAVE_SYS_FILE_H @HAVE_SYS_FILE_H@
 
 /* Define to 1 if you have the <sys/socket.h> header file. */
 #cmakedefine HAVE_SYS_SOCKET_H @HAVE_SYS_SOCKET_H@
 
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#cmakedefine HAVE_SYS_STAT_H @HAVE_SYS_STAT_H@
-
 /* Define to 1 if you have the <sys/syscall.h> header file. */
 #cmakedefine HAVE_SYS_SYSCALL_H @HAVE_SYS_SYSCALL_H@
 
 /* Define to 1 if you have the <sys/time.h> header file. */
 #cmakedefine HAVE_SYS_TIME_H @HAVE_SYS_TIME_H@
 
-/* Define to 1 if you have the <sys/types.h> header file. */
-#cmakedefine HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@
-
 /* Define to 1 if you have the <sys/un.h> header file. */
 #cmakedefine HAVE_SYS_UN_H @HAVE_SYS_UN_H@
 
 /* Define to 1 if you have the <thread.h> header file. */
 #cmakedefine HAVE_THREAD_H @HAVE_THREAD_H@
 
-/* Define to 1 if you have the C++11 <tuple> header file. */
-#cmakedefine HAVE_TUPLE @HAVE_TUPLE@
-
 /* Define to 1 if you have the C++11 <type_traits> header file. */
 #cmakedefine HAVE_TYPE_TRAITS @HAVE_TYPE_TRAITS@
 
 /* Define to 1 if you have the `vfprintf_s' function. */
 #cmakedefine HAVE_VFPRINTF_S @HAVE_VFPRINTF_S@
 
-/* Define to 1 if you have the `vsnprintf' function. */
-#cmakedefine HAVE_VSNPRINTF @HAVE_VSNPRINTF@
-
 /* Define to 1 if you have the `vsprintf_s' function. */
 #cmakedefine HAVE_VSPRINTF_S @HAVE_VSPRINTF_S@
 
 /* Select LFS mode (defined above) that shall be used or don't define it */
 #cmakedefine DCMTK_ENABLE_LFS @DCMTK_LFS_MODE@
 
-/* The size of a `double', as computed by sizeof. */
-#cmakedefine SIZEOF_DOUBLE @SIZEOF_DOUBLE@
-
-/* The size of a `float', as computed by sizeof. */
-#cmakedefine SIZEOF_FLOAT @SIZEOF_FLOAT@
-
 /* The size of a `int', as computed by sizeof. */
 #cmakedefine SIZEOF_INT @SIZEOF_INT@
 
 /* The size of a `long', as computed by sizeof. */
 #cmakedefine SIZEOF_LONG @SIZEOF_LONG@
 
-/* The size of a `short', as computed by sizeof. */
-#cmakedefine SIZEOF_SHORT @SIZEOF_SHORT@
-
 /* The size of a `void *', as computed by sizeof. */
 #cmakedefine SIZEOF_VOID_P @SIZEOF_VOID_P@
 
 #endif
 #endif
 
-/* Set typedefs as needed for JasPer library */
-#cmakedefine HAVE_UCHAR_TYPEDEF
-#ifndef HAVE_UCHAR_TYPEDEF
-typedef unsigned char uchar;
-#endif
-
-#cmakedefine HAVE_USHORT_TYPEDEF
-#ifndef HAVE_USHORT_TYPEDEF
-typedef unsigned short ushort;
-#endif
-
-#cmakedefine HAVE_UINT_TYPEDEF
-#ifndef HAVE_UINT_TYPEDEF
-typedef unsigned int uint;
-#endif
-
-#cmakedefine HAVE_ULONG_TYPEDEF
-#ifndef HAVE_ULONG_TYPEDEF
-typedef unsigned long ulong;
-#endif
-
 #cmakedefine HAVE_LONG_LONG
 #cmakedefine HAVE_UNSIGNED_LONG_LONG
 
@@ -682,63 +543,39 @@ typedef unsigned long ulong;
 #cmakedefine HAVE_UINT64_T @HAVE_UINT64_T@
 
  /* Additional settings for Borland C++ Builder */
-#ifdef __BORLANDC__
+
+#if defined(__BORLANDC__) && (!defined(_WIN64) || !defined(__MINGW64__))
+#define HAVE_CLASSIC_BORLAND_COMPILER
+#endif
+
+#ifdef HAVE_CLASSIC_BORLAND_COMPILER
+#define _MSC_VER 1200       /* Treat Borland C++ 5.5 as MSVC6. */
 #define _stricmp stricmp    /* _stricmp in MSVC is stricmp in Borland C++ */
 #define _strnicmp strnicmp  /* _strnicmp in MSVC is strnicmp in Borland C++ */
-    #pragma warn -8027      /* disable Warning W8027 "functions containing while are not expanded inline" */
-    #pragma warn -8004      /* disable Warning W8004 "variable is assigned a value that is never used" */
-    #pragma warn -8012      /* disable Warning W8012 "comparing signed and unsigned values" */
+#pragma warn -8027          /* disable Warning W8027 "functions containing while are not expanded inline" */
+#pragma warn -8004          /* disable Warning W8004 "variable is assigned a value that is never used" */
+#pragma warn -8012          /* disable Warning W8012 "comparing signed and unsigned values" */
 #ifdef WITH_THREADS
 #define __MT__              /* required for _beginthreadex() API in <process.h> */
 #define _MT                 /* required for _errno on BCB6 */
 #endif
-#define HAVE_PROTOTYPE_MKTEMP 1
-#undef HAVE_SYS_UTIME_H
-#define _MSC_VER 1200       /* Treat Borland C++ 5.5 as MSVC6. */
-#endif /* __BORLANDC__ */
-
-/* Platform specific settings for Visual C++
- * By default, enable ANSI standard C++ includes on Visual C++ 6 and newer
- *   _MSC_VER == 1100 on Microsoft Visual C++ 5.0
- *   _MSC_VER == 1200 on Microsoft Visual C++ 6.0
- *   _MSC_VER == 1300 on Microsoft Visual C++ 7.0
- *   _MSC_VER == 1310 on Microsoft Visual C++ 7.1
- *   _MSC_VER == 1400 on Microsoft Visual C++ 8.0
- */
+#endif /* HAVE_CLASSIC_BORLAND_COMPILER */
 
-#ifdef _MSC_VER
-#if _MSC_VER <= 1200 /* Additional settings for VC6 and older */
-/* disable warning that return type for 'identifier::operator ->' is not a UDT or reference to a UDT */
-    #pragma warning( disable : 4284 )
-#define HAVE_OLD_INTERLOCKEDCOMPAREEXCHANGE 1
-#else
-#define HAVE_VSNPRINTF 1
-#endif /* _MSC_VER <= 1200 */
+/* Platform specific settings for Visual C++ */
 
+#ifdef _MSC_VER
     #pragma warning( disable : 4251 )  /* disable warnings about needed dll-interface */
                                        /* http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html */
     #pragma warning( disable : 4099 )  /* disable warning about mismatched class and struct keywords */
                                        /* http://alfps.wordpress.com/2010/06/22/cppx-is-c4099-really-a-sillywarning-disabling-msvc-sillywarnings */
     #pragma warning( disable : 4521 )  /* disable warnings about multiple copy constructors and assignment operators,*/
     #pragma warning( disable : 4522 )  /* since these are sometimes necessary for correct overload resolution*/
-
-#if _MSC_VER >= 1400                   /* Additional settings for Visual Studio 2005 and newer */
     #pragma warning( disable : 4996 )  /* disable warnings about "deprecated" C runtime functions */
 #if _MSC_VER < 1900                    /* Warning only available before Visual Studio 2015 */
     #pragma warning( disable : 4351 )  /* disable warnings about "new behavior" when initializing the elements of an array */
 #endif /* _MSC_VER < 1900 */
-#endif /* _MSC_VER >= 1400 */
 #endif /* _MSC_VER */
 
-/* Define if ANSI standard C++ includes use std namespace */
-#cmakedefine HAVE_STD_NAMESPACE @HAVE_STD_NAMESPACE@
-
-/* Define if the compiler supports std::nothrow */
-#cmakedefine HAVE_STD__NOTHROW @HAVE_STD__NOTHROW@
-
-/* Define if the compiler supports operator delete (std::nothrow) */
-#cmakedefine HAVE_NOTHROW_DELETE @HAVE_NOTHROW_DELETE@
-
 /* Define if the compiler supports static_assert */
 #cmakedefine HAVE_STATIC_ASSERT @HAVE_STATIC_ASSERT@
 
@@ -760,9 +597,6 @@ typedef unsigned long ulong;
 /* Define if the compiler supports __declspec(deprecated("message")) */
 #cmakedefine HAVE_DECLSPEC_DEPRECATED_MSG @HAVE_DECLSPEC_DEPRECATED_MSG@
 
-/* Define if your system has a prototype for std::vfprintf in stdarg.h */
-#cmakedefine HAVE_PROTOTYPE_STD__VFPRINTF @HAVE_PROTOTYPE_STD__VFPRINTF@
-
 /* Define if your system has off64_t */
 #cmakedefine HAVE_OFF64_T @HAVE_OFF64_T@
 
@@ -775,39 +609,73 @@ typedef unsigned long ulong;
 /* Define if your system uses _pclose instead of pclose */
 #cmakedefine HAVE_PCLOSE @HAVE_PCLOSE@
 
-/* Define if your system provides sigjmp_buf as conditional jmp_buf alternative */
-#cmakedefine HAVE_SIGJMP_BUF @HAVE_SIGJMP_BUF@
-
 /* Define if we can use C++11 */
 #cmakedefine HAVE_CXX11 @HAVE_CXX11@
 
-#if defined(HAVE_CXX11) && defined(__cplusplus) && __cplusplus < 201103L
+#if defined(HAVE_CXX11)
+# if defined(_MSVC_LANG)
+#  if _MSVC_LANG < 201103L
+#error \
+DCMTK was configured to use C++11 features, but your compiler does not or was not configured to provide them.
+#  endif
+# elif defined(__cplusplus)
+#  if __cplusplus < 201103L
 #error \
 DCMTK was configured to use C++11 features, but your compiler does not or was not configured to provide them.
+#  endif
+# endif
 #endif
 
 /* Define if we can use C++14 */
 #cmakedefine HAVE_CXX14 @HAVE_CXX14@
 
-#if defined(HAVE_CXX14) && defined(__cplusplus) && __cplusplus < 201402L
+#if defined(HAVE_CXX14)
+# if defined(_MSVC_LANG)
+#  if _MSVC_LANG < 201402L
 #error \
 DCMTK was configured to use C++14 features, but your compiler does not or was not configured to provide them.
+#  endif
+# elif defined(__cplusplus)
+#  if __cplusplus < 201402L
+#error \
+DCMTK was configured to use C++14 features, but your compiler does not or was not configured to provide them.
+#  endif
+# endif
 #endif
 
 /* Define if we can use C++17 */
 #cmakedefine HAVE_CXX17 @HAVE_CXX17@
 
-#if defined(HAVE_CXX17) && defined(__cplusplus) && __cplusplus < 201703L
+#if defined(HAVE_CXX17)
+# if defined(_MSVC_LANG)
+#  if _MSVC_LANG < 201703L
 #error \
 DCMTK was configured to use C++17 features, but your compiler does not or was not configured to provide them.
+#  endif
+# elif defined(__cplusplus)
+#  if __cplusplus < 201703L
+#error \
+DCMTK was configured to use C++17 features, but your compiler does not or was not configured to provide them.
+#  endif
+# endif
 #endif
 
+
 /* Define if we can use C++20 */
 #cmakedefine HAVE_CXX20 @HAVE_CXX20@
 
-#if defined(HAVE_CXX20) && defined(__cplusplus) && __cplusplus < 202002L
+#if defined(HAVE_CXX20)
+# if defined(_MSVC_LANG)
+#  if _MSVC_LANG < 202002L
 #error \
 DCMTK was configured to use C++20 features, but your compiler does not or was not configured to provide them.
+#  endif
+# elif defined(__cplusplus)
+#  if __cplusplus < 202002L
+#error \
+DCMTK was configured to use C++20 features, but your compiler does not or was not configured to provide them.
+#  endif
+# endif
 #endif
 
 /* Define if the compiler supports __alignof__ */
@@ -867,9 +735,6 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 /* Define if we are supposed to use STL's atomic */
 #cmakedefine HAVE_STL_ATOMIC @HAVE_STL_ATOMIC@
 
-/* Define if the input iterator category is supported */
-#cmakedefine HAVE_CONTIGUOUS_ITERATOR_CATEGORY @HAVE_CONTIGUOUS_ITERATOR_CATEGORY@
-
 /* Feature Tests for the OpenSSL Library */
 
 /* Define if your OpenSSL library provides the RAND_egd function */
@@ -911,13 +776,13 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 /* Define if we have the <openssl/provider.h> header file*/
 #cmakedefine HAVE_OPENSSL_PROVIDER_H @HAVE_OPENSSL_PROVIDER_H@
 
-
 /* Historical C/C++ language features and APIs that are guaranteed by C++98,
- * C89, or POSIX.1-2001 for Posix platforms, and thus not tested anymore.
+ * C99, or POSIX.1-2001 for Posix platforms, or are not used anywhere in DCMTK,
+ * and thus not tested anymore.
  * These macros are deprecated and will be removed from a future version.
  */
-
 #if defined(POISON_DEPRECATED_FEATURE_MACROS) && defined(__GNUC__)
+#pragma GCC poison HAVE_ACCESS
 #pragma GCC poison HAVE_ASSERT_H
 #pragma GCC poison HAVE_BIDIRECTIONAL_ITERATOR_CATEGORY
 #pragma GCC poison HAVE_CLASS_TEMPLATE
@@ -934,12 +799,14 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 #pragma GCC poison HAVE_DYNAMIC_CAST
 #pragma GCC poison HAVE_ERRNO_H
 #pragma GCC poison HAVE_EXPLICIT_TEMPLATE_SPECIALIZATION
+#pragma GCC poison HAVE_FCNTL_H
 #pragma GCC poison HAVE_FENV_H
 #pragma GCC poison HAVE_FLOAT_H
 #pragma GCC poison HAVE_FORWARD_ITERATOR_CATEGORY
 #pragma GCC poison HAVE_FSTREAM
 #pragma GCC poison HAVE_FUNCTION_TEMPLATE
 #pragma GCC poison HAVE_GETENV
+#pragma GCC poison HAVE_GETPID
 #pragma GCC poison HAVE_INPUT_ITERATOR_CATEGORY
 #pragma GCC poison HAVE_INTTYPES_H
 #pragma GCC poison HAVE_IOMANIP
@@ -957,40 +824,59 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 #pragma GCC poison HAVE_MEMCPY
 #pragma GCC poison HAVE_MEMMOVE
 #pragma GCC poison HAVE_MEMSET
+#pragma GCC poison HAVE_MKTEMP
+#pragma GCC poison HAVE_NOTHROW_DELETE
 #pragma GCC poison HAVE_OUTPUT_ITERATOR_CATEGORY
 #pragma GCC poison HAVE_PROTOTYPE_ISINF
 #pragma GCC poison HAVE_PROTOTYPE_ISNAN
+#pragma GCC poison HAVE_PROTOTYPE_MKTEMP
+#pragma GCC poison HAVE_PROTOTYPE_STD__ISINF
+#pragma GCC poison HAVE_PROTOTYPE_STD__ISNAN
+#pragma GCC poison HAVE_PROTOTYPE_STD__VFPRINTF
+#pragma GCC poison HAVE_PROTOTYPE_VSNPRINTF
 #pragma GCC poison HAVE_RANDOM_ACCESS_ITERATOR_CATEGORY
 #pragma GCC poison HAVE_REINTERPRET_CAST
 #pragma GCC poison HAVE_SETJMP_H
 #pragma GCC poison HAVE_SIGNAL_H
 #pragma GCC poison HAVE_SSTREAM
+#pragma GCC poison HAVE_STAT
 #pragma GCC poison HAVE_STATIC_CAST
 #pragma GCC poison HAVE_STATIC_TEMPLATE_METHOD
 #pragma GCC poison HAVE_STDARG_H
 #pragma GCC poison HAVE_STDBOOL_H
 #pragma GCC poison HAVE_STDDEF_H
+#pragma GCC poison HAVE_STDINT_H
 #pragma GCC poison HAVE_STDIO_H
 #pragma GCC poison HAVE_STDLIB_H
+#pragma GCC poison HAVE_STD_NAMESPACE
+#pragma GCC poison HAVE_STD__NOTHROW
 #pragma GCC poison HAVE_STRCHR
+#pragma GCC poison HAVE_STRDUP
 #pragma GCC poison HAVE_STRERROR
 #pragma GCC poison HAVE_STRING_H
 #pragma GCC poison HAVE_STRSTR
 #pragma GCC poison HAVE_STRSTREAM
 #pragma GCC poison HAVE_STRTOUL
+#pragma GCC poison HAVE_SYS_STAT_H
+/* #pragma GCC poison HAVE_SYS_TYPES_H */  /* this macro is used in some Linux system header files. */
 #pragma GCC poison HAVE_TEMPNAM
 #pragma GCC poison HAVE_TIME_H
 #pragma GCC poison HAVE_TMPNAM
 #pragma GCC poison HAVE_TYPENAME
 #pragma GCC poison HAVE_VPRINTF
+#pragma GCC poison HAVE_VSNPRINTF
 #pragma GCC poison HAVE_WCHAR_H
 #pragma GCC poison HAVE_WCSTOMBS
 #pragma GCC poison HAVE_WCTYPE_H
 #pragma GCC poison SIZEOF_CHAR
+#pragma GCC poison SIZEOF_DOUBLE
+#pragma GCC poison SIZEOF_FLOAT
+#pragma GCC poison SIZEOF_SHORT
 #pragma GCC poison STDC_HEADERS
 #endif
 
 #if !defined(POISON_DEPRECATED_FEATURE_MACROS) || !defined(__GNUC__)
+#define HAVE_ACCESS 1
 #define HAVE_ASSERT_H 1
 #define HAVE_BIDIRECTIONAL_ITERATOR_CATEGORY 1
 #define HAVE_CLASS_TEMPLATE 1
@@ -1007,12 +893,14 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 #define HAVE_DYNAMIC_CAST 1
 #define HAVE_ERRNO_H 1
 #define HAVE_EXPLICIT_TEMPLATE_SPECIALIZATION 1
+#define HAVE_FCNTL_H 1
 #define HAVE_FENV_H 1
 #define HAVE_FLOAT_H 1
 #define HAVE_FORWARD_ITERATOR_CATEGORY 1
 #define HAVE_FSTREAM 1
 #define HAVE_FUNCTION_TEMPLATE 1
 #define HAVE_GETENV 1
+#define HAVE_GETPID 1
 #define HAVE_INPUT_ITERATOR_CATEGORY 1
 #define HAVE_INTTYPES_H 1
 #define HAVE_IOMANIP 1
@@ -1030,32 +918,47 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 #define HAVE_MEMCPY 1
 #define HAVE_MEMMOVE 1
 #define HAVE_MEMSET 1
+#define HAVE_MKTEMP 1
+#define HAVE_NOTHROW_DELETE 1
 #define HAVE_OUTPUT_ITERATOR_CATEGORY 1
 #define HAVE_PROTOTYPE_ISINF 1
 #define HAVE_PROTOTYPE_ISNAN 1
+#define HAVE_PROTOTYPE_MKTEMP 1
+#define HAVE_PROTOTYPE_STD__ISINF 1
+#define HAVE_PROTOTYPE_STD__ISNAN 1
+#define HAVE_PROTOTYPE_STD__VFPRINTF 1
+#define HAVE_PROTOTYPE_VSNPRINTF 1
 #define HAVE_RANDOM_ACCESS_ITERATOR_CATEGORY 1
 #define HAVE_REINTERPRET_CAST 1
 #define HAVE_SETJMP_H 1
 #define HAVE_SIGNAL_H 1
 #define HAVE_SSTREAM 1
+#define HAVE_STAT 1
 #define HAVE_STATIC_CAST 1
 #define HAVE_STATIC_TEMPLATE_METHOD 1
 #define HAVE_STDARG_H 1
 #define HAVE_STDBOOL_H 1
 #define HAVE_STDDEF_H 1
+#define HAVE_STDINT_H 1
 #define HAVE_STDIO_H 1
 #define HAVE_STDLIB_H 1
+#define HAVE_STD_NAMESPACE 1
+#define HAVE_STD__NOTHROW 1
 #define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
 #define HAVE_STRERROR 1
 #define HAVE_STRING_H 1
 #define HAVE_STRSTR 1
 #define HAVE_STRSTREAM 1
 #define HAVE_STRTOUL 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
 #define HAVE_TEMPNAM 1
 #define HAVE_TIME_H 1
 #define HAVE_TMPNAM 1
 #define HAVE_TYPENAME 1
 #define HAVE_VPRINTF 1
+#define HAVE_VSNPRINTF 1
 #define HAVE_WCHAR_H 1
 #define HAVE_WCSTOMBS 1
 #define HAVE_WCTYPE_H 1
@@ -1069,29 +972,56 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 
 #if defined(POISON_DEPRECATED_FEATURE_MACROS) && defined(__GNUC__)
 #pragma GCC poison C_INLINE
+#pragma GCC poison HAVE_BCMP
 #pragma GCC poison HAVE_BCOPY
+#pragma GCC poison HAVE_CONTIGUOUS_ITERATOR_CATEGORY
+#pragma GCC poison HAVE_DECLARATION_FP_EXCEPT_T
 #pragma GCC poison HAVE_DECLARATION_STD__IOS_BASE__OPENMODE
 #pragma GCC poison HAVE_DOPRNT
 #pragma GCC poison HAVE_EMPTY_ARGC_ARGV
+#pragma GCC poison HAVE_FINITE
 #pragma GCC poison HAVE_FSTREAM_H
+#pragma GCC poison HAVE_GETRUSAGE
+#pragma GCC poison HAVE_INDEX
+#pragma GCC poison HAVE_INTP_ACCEPT
+#pragma GCC poison HAVE_INTP_GETSOCKOPT
 #pragma GCC poison HAVE_IOMANIP_H
 #pragma GCC poison HAVE_IOSTREAM_H
 #pragma GCC poison HAVE_IOS_NOCREATE
+#pragma GCC poison HAVE_ITOA
 #pragma GCC poison HAVE_LIBIOSTREAM
+#pragma GCC poison HAVE_LIBNSL
+#pragma GCC poison HAVE_LIBSOCKET
+#pragma GCC poison HAVE_LISTEN
 #pragma GCC poison HAVE_LONGLONG
+#pragma GCC poison HAVE_MALLOC_H
 #pragma GCC poison HAVE_MEMORY_H
 #pragma GCC poison HAVE_NDIR_H
 #pragma GCC poison HAVE_NEW_H
 #pragma GCC poison HAVE_OLD_READDIR_R
+#pragma GCC poison HAVE_PROTOTYPE_FINITE
+#pragma GCC poison HAVE_PROTOTYPE_MKSTEMP
+#pragma GCC poison HAVE_PROTOTYPE_NANOSLEEP
 #pragma GCC poison HAVE_PROTOTYPE_STD__FINITE
 #pragma GCC poison HAVE_PROTOTYPE_WAIT3
+#pragma GCC poison HAVE_PROTOTYPE_FEENABLEEXCEPT
+#pragma GCC poison HAVE_PROTOTYPE__FPCLASSF
+#pragma GCC poison HAVE_RINDEX
+#pragma GCC poison HAVE_SIGJMP_BUF
 #pragma GCC poison HAVE_SSTREAM_H
 #pragma GCC poison HAVE_STAT_H
 #pragma GCC poison HAVE_STREAMBUF_H
 #pragma GCC poison HAVE_STRSTREAM_H
 #pragma GCC poison HAVE_STRSTREA_H
+#pragma GCC poison HAVE_SYSTEM_ERROR
+#pragma GCC poison HAVE_SYS_ERRNO_H
 #pragma GCC poison HAVE_SYS_NDIR_H
+#pragma GCC poison HAVE_TUPLE
+#pragma GCC poison HAVE_UCHAR_TYPEDEF
+#pragma GCC poison HAVE_UINT_TYPEDEF
 #pragma GCC poison HAVE_ULONGLONG
+#pragma GCC poison HAVE_ULONG_TYPEDEF
+#pragma GCC poison HAVE_USHORT_TYPEDEF
 #pragma GCC poison HAVE_WAIT3
 #pragma GCC poison INCLUDE_LIBC_H_AS_CXX
 #pragma GCC poison INCLUDE_MATH_H_AS_CXX
@@ -1099,37 +1029,68 @@ DCMTK was configured to use C++20 features, but your compiler does not or was no
 #pragma GCC poison TM_IN_SYS_TIME
 #endif
 
+#if !defined(POISON_DEPRECATED_FEATURE_MACROS) || !defined(__GNUC__)
 /* #undef C_INLINE */
+/* #undef HAVE_BCMP */
 /* #undef HAVE_BCOPY */
+/* #undef HAVE_CONTIGUOUS_ITERATOR_CATEGORY */
+/* #undef HAVE_DECLARATION_FP_EXCEPT_T */
 /* #undef HAVE_DECLARATION_STD__IOS_BASE__OPENMODE */
 /* #undef HAVE_DOPRNT */
 /* #undef HAVE_EMPTY_ARGC_ARGV */
+/* #undef HAVE_FINITE */
 /* #undef HAVE_FSTREAM_H */
+/* #undef HAVE_GETRUSAGE */
+/* #undef HAVE_INDEX */
+/* #undef HAVE_INTP_ACCEPT */
+/* #undef HAVE_INTP_GETSOCKOPT */
 /* #undef HAVE_IOMANIP_H */
 /* #undef HAVE_IOSTREAM_H */
 /* #undef HAVE_IOS_NOCREATE */
+/* #undef HAVE_ITOA */
 /* #undef HAVE_LIBIOSTREAM */
+/* #undef HAVE_LIBNSL */
+/* #undef HAVE_LIBSOCKET */
+/* #undef HAVE_LISTEN */
 /* #undef HAVE_LONGLONG */
+/* #undef HAVE_MALLOC_H */
 /* #undef HAVE_MEMORY_H */
 /* #undef HAVE_NDIR_H */
 /* #undef HAVE_NEW_H */
 /* #undef HAVE_OLD_READDIR_R */
+/* #undef HAVE_PROTOTYPE_FINITE */
+/* #undef HAVE_PROTOTYPE_MKSTEMP */
+/* #undef HAVE_PROTOTYPE_NANOSLEEP */
 /* #undef HAVE_PROTOTYPE_STD__FINITE */
 /* #undef HAVE_PROTOTYPE_WAIT3 */
+/* #undef HAVE_PROTOTYPE_FEENABLEEXCEPT */
+/* #undef HAVE_PROTOTYPE__FPCLASSF */
+/* #undef HAVE_RINDEX */
+/* #undef HAVE_SIGJMP_BUF */
 /* #undef HAVE_SSTREAM_H */
 /* #undef HAVE_STAT_H */
 /* #undef HAVE_STREAMBUF_H */
 /* #undef HAVE_STRSTREAM_H */
 /* #undef HAVE_STRSTREA_H */
+/* #undef HAVE_SYSTEM_ERROR */
+/* #undef HAVE_SYS_ERRNO_H */
 /* #undef HAVE_SYS_NDIR_H */
+/* #undef HAVE_TUPLE */
+/* #undef HAVE_UCHAR_TYPEDEF */
+/* #undef HAVE_UINT_TYPEDEF */
 /* #undef HAVE_ULONGLONG */
+/* #undef HAVE_ULONG_TYPEDEF */
+/* #undef HAVE_USHORT_TYPEDEF */
 /* #undef HAVE_WAIT3 */
 /* #undef INCLUDE_LIBC_H_AS_CXX */
 /* #undef INCLUDE_MATH_H_AS_CXX */
 /* #undef RETSIGTYPE */
 /* #undef TM_IN_SYS_TIME */
 /* #undef __CHAR_UNSIGNED__ */
-
+#define SIZEOF_DOUBLE 8
+#define SIZEOF_FLOAT 4
+#define SIZEOF_SHORT 2
+#endif
 
 /* Historical feature tests for BSD socket functions, which exist on POSIX
  * systems and on Windows. These are not tested anymore.
index d6c8ad95425685395dbc2ebdb21489856d946975..5e440aa4debe1ec362469b513b3d3bbf57f3806c 100644 (file)
@@ -1,5 +1,5 @@
 # Minimum CMake version required
-cmake_minimum_required(VERSION 3.7.0...3.31.2 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.7.0...4.2.0 FATAL_ERROR)
 
 # Declare project
 project(DCMTK)
@@ -134,6 +134,7 @@ if(CMAKE_CROSSCOMPILING)
       get_filename_component(FILE "${DICTIONARY}" NAME)
       set(DCMDICTPATH "${DCMDICTPATH}:${ANDROID_TEMPORARY_FILES_LOCATION}/${FILE}")
     endforeach()
+    set(DCMICONVPATH "${ANDROID_TEMPORARY_FILES_LOCATION}/data")
     configure_file("${DCMTK_SOURCE_DIR}/CMake/CTest/CTestCustomAndroid.cmake.in"
       "${DCMTK_BINARY_DIR}/CTestCustom.cmake" ESCAPE_QUOTES @ONLY
     )
index d40a73c60ddef56736f0cf61e19ee94d9d45c9c6..bacd5c2a8abc73c02845f43d480e496ffbfbb254 100644 (file)
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -5,7 +5,7 @@ Unless otherwise specified, the DCMTK software package has the following
 copyright:
 
 /*
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.
  *
  *  This software and supporting documentation were developed by
@@ -506,8 +506,8 @@ The dcmrt sub-package is covered by the following copyright
 
 ---------------------------------------------------------------------------
 
-Copyright (C) 2008-2024, OFFIS e.V. and ICSMED AG, Oldenburg, Germany.
-Copyright (C) 2013-2024, J. Riesmeier, Oldenburg, Germany.
+Copyright (C) 2008-2025, OFFIS e.V. and ICSMED AG, Oldenburg, Germany.
+Copyright (C) 2013-2025, J. Riesmeier, Oldenburg, Germany.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -543,7 +543,7 @@ Parts of the dcmsr sub-package are covered by the following copyright
 
 ---------------------------------------------------------------------------
 
-Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany.
+Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -873,7 +873,6 @@ is derived from an implementation with the following license:
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-
 ---------------------------------------------------------------------------
 
 The implementation of the getLastErrorString() function in ofstub.cc
@@ -882,6 +881,35 @@ the BSD license (without further specification).
 
 ---------------------------------------------------------------------------
 
+The implementation of the JSON to DICOM converter available uses the
+"jsmn" JSON parser library with the following license:
+
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+---------------------------------------------------------------------------
+
 Finally, DCMTK can be configured and compiled to make use of a number of
 optional external libraries that, when available, provide added functionality
 such as compression, encryption, or support for certain image formats.
diff --git a/CREDITS b/CREDITS
index 6241d52f646ca5bd804d7a704e4d8226817c0bfd..63cbcb52b6d8212ae17758a111c299632b4e0a1b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -6,7 +6,7 @@ We would like to thank the following individuals, companies and organizations
 Open Source DICOM Toolkit DCMTK:
 
 Carl Zeiss Meditec: The preparation and publication of the DCMTK 3.6.2 release
-  as well as several extensions in wlmscpfs and dcmqrscp were supported by
+  as well as several extensions in "wlmscpfs" and "dcmqrscp" were supported by
   funding from Carl Zeiss Meditec AG (Muenchen, Germany).
 
 DKFZ: The work on the DCMTK module "dcmrt" was supported in part by funding
@@ -17,7 +17,7 @@ Epilepsieforschung: The Gesellschaft fuer Epilepsieforschung e.V. (Bielefeld,
   tool "dcmrecv" and the underlying class "DcmStorageSCP".
 
 GE Aviation: GE Aviation supported DCMTK by sponsoring the development of the
-  dcmect library and basic concatenation support in dcmfg.
+  "dcmect" library and basic concatenation support in "dcmfg".
 
 ICSMED: From 2006 to 2012, the work on the DCMTK was supported by employees of
   the ICSMED AG (Oldenburg, Germany), a spin-off from the OFFIS institute.
@@ -35,7 +35,7 @@ M. Malaterre: The GDCM developer Mathieu Malaterre (Lyon, France) regularly
   reports possible issues to the DCMTK team.  He was also responsible for
   packaging the DCMTK library and tools for the Debian operating system.
 
-Mathworks: Funded implementation of TLS support in getscu, introduced
+Mathworks: Funded implementation of TLS support in "getscu", introduced
   in DCMTK 3.6.9.
 
 Medpace: Funded the development of the "dcm2img" tool introduced in DCMTK
@@ -62,6 +62,10 @@ SlicerDMRI: The work on DCMTK Tractography modules was supported in part by
   initiative, to project Open Source Diffusion MRI Technology For Brain Cancer
   Research, award U01 CA199459.
 
+Twisted Ceptors: Funded the extension of the "storescp" application by the
+  "--max-associations" option that allows the user to limit the number of
+  clients served in parallel when operating in "--fork mode".
+
 VISUS: The work on various extensions of the DCMTK was supported in part by
   funding from the VISUS Technology Transfer GmbH (Bochum, Germany).
 
@@ -72,4 +76,4 @@ YXLON: The work on the initial version of the DICONDE data dictionary was
 Please note that this list does not claim to be exhaustive.  Just send us an
 email if you think that you or your company/organization should also be listed.
 
-DCMTK Team, 2024-11-21
+DCMTK Team, 2025-12-15
diff --git a/INSTALL b/INSTALL
index 7de38bfbf1be38fc805f299142529ffce36a6d65..d51d541a2a5e348e525397066db5f7df9aad40a7 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -9,7 +9,7 @@ PRE-REQUISITES
 The DICOM toolkit (DCMTK) needs to be compiled with a C++ compiler.  We
 recommend using the GNU C++ compiler in versions higher than 9.5.0 (most of the
 development for this release was done using GNU gcc 12.2.0 on Debian Linux and
-GNU gcc 13.2.0 on Ubuntu Linux).  The software is also known to compile using
+GNU gcc 13.3.0 on Ubuntu Linux).  The software is also known to compile using
 Clang and Microsoft Visual Studio.
 
 Compatibility with other C++ compilers is unknown, however, we have tried to
@@ -28,7 +28,7 @@ Microsoft Windows
 The DCMTK software can be compiled under a native Microsoft Windows environment
 (see section "Microsoft Windows with CMake" below for more information).
 
-The current DCMTK software release 3.6.9 successfully compiles on the following
+The current DCMTK software release 3.7.0 successfully compiles on the following
 operating system / hardware / compiler combinations:
 
    Windows 10      / Intel x86    / Microsoft Visual C++ 2017 Community (VS 15)
@@ -54,10 +54,57 @@ operating system / hardware / compiler combinations:
 Unix (or lookalikes)
 --------------------
 
-The current DCMTK software release 3.6.9 successfully compiles on the following
+The current DCMTK software release 3.7.0 successfully compiles on the following
 operating system / hardware / compiler combinations using the instructions
 given below:
 
+   FreeBSD 14.3    / amd64|x86_64 / Clang 19.1.7
+   Linux 5.14.0    / amd64|x86_64 / GNU gcc 11.5.0    (AlmaLinux 9.6)
+   Linux 6.1.0     / Intel x86    / Clang 14.0.6      (Debian 12)
+   Linux 6.1.0     / Intel x86    / GNU gcc 12.2.0    (Debian 12)
+   Linux 6.1.0     / amd64|x86_64 / Clang 14.0.6      (Debian 12)
+   Linux 6.1.0     / amd64|x86_64 / GNU gcc 12.2.0    (Debian 12)
+   Linux 6.1.0     / amd64|x86_64 / GNU gcc 13.2.1    (Alpine 3.20 musl libc)
+   Linux 6.8.0     / amd64|x86_64 / GNU gcc 11.5.0    (Ubuntu 24.04.3 LTS)
+   Linux 6.8.0     / amd64|x86_64 / GNU gcc 12.4.0    (Ubuntu 24.04.3 LTS)
+   Linux 6.8.0     / amd64|x86_64 / GNU gcc 13.3.0    (Ubuntu 24.04.3 LTS)
+   Linux 6.8.0     / amd64|x86_64 / GNU gcc 14.2.0    (Ubuntu 24.04.3 LTS)
+   Linux 6.8.0     / amd64|x86_64 / Clang 18.1.3      (Ubuntu 24.04.3 LTS)
+   Linux 6.8.0     / s390x        / GNU gcc 13.3.0    (Ubuntu 24.04.2 LTS)
+   Linux 6.8.0     / s390x        / Clang 18.1.3      (Ubuntu 24.04.2 LTS)
+   MacOS X 15.5    / amd64|x86_64 / Apple Clang 17.0.0
+   MacOS X 15.5    / amd64|x86_64 / GNU gcc 15.2.0
+   MacOS X 15.5    / arm64        / Apple Clang 17.0.0
+   MacOS X 15.5    / arm64        / GNU gcc 15.2.0
+   NetBSD 10.1     / amd64|x86_64 / Clang 18.1.8
+   NetBSD 10.1     / amd64|x86_64 / GNU gcc 10.5.0
+   OpenBSD 7.7     / amd64|x86_64 / Clang 16.0.6
+   OpenIndiana     / amd64|x86_64 / GNU gcc 14.3.0    (OpenIndiana 2025.06)
+
+
+Cross Compiling
+---------------
+
+For target platforms other than Android, see section "CROSS COMPILING WITH
+CMAKE" below.  For Android, the current DCMTK release can be cross-compiled
+targeting the following platform:
+
+   Android         / arm64        / Clang 18.0.1      (API 35, ABI arm64-v8a)
+
+Cross compiling support with running configuration and unit tests is provided
+using CMake and requires the use of the Android emulator or Wine when targeting
+Android or Windows respectively.  Other versions of Android may also work,
+but the above mentioned one is currently the only one that is being
+regularly tested.
+
+
+Other Platforms
+---------------
+
+The previous release DCMTK 3.6.9 was also tested on the following platforms
+that may still work, but were not tested again for this release:
+
+   Android         / arm64        / GNU gcc 12.2.0    (API 24, ABI arm64-v8a)
    FreeBSD 14.1    / amd64|x86_64 / Clang 18.1.5
    Linux 4.19.0    / ppc64le      / IBM XL C/C++ 16.1.1 Community
    Linux 5.14.0    / amd64|x86_64 / GNU gcc 11.4.1    (AlmaLinux 9.4)
@@ -81,25 +128,6 @@ given below:
    OpenBSD 7.5     / amd64|x86_64 / Clang 16.0.6
    OpenIndiana     / amd64|x86_64 / GNU gcc 13.2.0    (OpenIndiana 2023.10)
 
-
-Cross Compiling
----------------
-
-For target platforms other than Android, see section "CROSS COMPILING WITH
-CMAKE" below.  For Android, the current DCMTK release can be cross-compiled
-targeting the following platform:
-
-   Android         / arm64        / GNU gcc 12.2.0    (API 24, ABI arm64-v8a)
-
-Cross compiling support with running configuration and unit tests is provided
-using CMake and requires the use of the Android emulator or Wine when targeting
-Android or Windows respectively.  Other versions of Android will most likely
-also work, but the above mentioned one is currently the only one that is being
-regularly tested.
-
-Other Platforms
----------------
-
 The previous release DCMTK 3.6.8 was also tested on the following platforms
 that may still work, but were not tested again for this release:
 
@@ -134,33 +162,6 @@ that may still work, but were not tested again for this release:
    Windows 7       / amd64|x86_64 / Microsoft Visual C++ 2019 Community (VS 16)
    Windows 7       / amd64|x86_64 / MinGW gcc 9.2.0 (x86_64-w64-mingw32)
 
-The previous release DCMTK 3.6.7 was also tested on the following platforms
-that may still work, but were not tested again for this release:
-
-   Windows 7       / Intel x86    / Microsoft Visual C++ 2010 Express (VS 10)
-   Windows 7       / amd64|x86_64 / Microsoft Visual C++ 2010 Express (VS 10)
-   Windows 7       / amd64|x86_64 / Cygwin GCC 7.4.0   (x86_64-pc-cygwin)
-   Windows 10      / Intel x86    / MinGW gcc 11.2.0   (i686-w64-mingw32)
-   Windows 10      / Intel x86    / MinGW Clang 13.0.0 (i686-w64-windows-gnu)
-   Windows 10      / amd64|x86_64 / MinGW gcc 11.2.0   (x86_64-w64-mingw32)
-   Windows 10      / amd64|x86_64 / MinGW Clang 13.0.0 (x86_64-w64-windows-gnu)
-   FreeBSD 13.0    / amd64|x86_64 / Clang 11.0.1
-   Linux 4.19.0    / amd64|x86_64 / Clang 7.0.1       (Debian 10)
-   Linux 4.19.0    / amd64|x86_64 / GNU 10.3.1    (Alpine 3.15.0 with musl libc)
-   Linux 4.19.0    / amd64|x86_64 / GNU gcc 8.3.0     (Debian 10)
-   Linux 4.19.0    / amd64|x86_64 / GNU gcc 8.3.0     (Debian 10)
-   Linux 5.10.0    / Intel x86    / GNU gcc 10.2.1    (Debian 11)
-   Linux 5.4.0     / amd64|x86_64 / Clang 10.0.0      (Ubuntu 20.04)
-   Linux 5.4.0     / amd64|x86_64 / Clang 9.0.1       (Ubuntu 20.04)
-   Linux 5.4.0     / amd64|x86_64 / GNU gcc 10.3.0    (Ubuntu 20.04)
-   Linux 5.4.0     / amd64|x86_64 / GNU gcc 9.3.0     (Ubuntu 20.04)
-   Linux 5.13.0    / amd64|x86_64 / Clang 13.0.0-2    (Ubuntu 21.10)
-   Linux 5.13.0    / amd64|x86_64 / GNU gcc 11.2.0    (Ubuntu 21.10)
-   MacOS X 10.15   / amd64|x86_64 / Apple Clang 11.0.0
-   MacOS X 10.15   / amd64|x86_64 / GNU gcc 9.2.0
-   NetBSD 9.0      / amd64|x86_64 / Clang 10.0.1
-   NetBSD 9.0      / amd64|x86_64 / GNU gcc 7.5.0
-   OpenBSD 7.0     / amd64|x86_64 / Clang 11.1.1
 
 Earlier releases of the DCMTK are known to also compile on further platforms,
 which are not available to us for testing purposes any more, e.g. AIX, HP-UX,
@@ -199,7 +200,7 @@ underlying cryptographic routines and the TLS protocol implementation.
 
 This release of DCMTK requires OpenSSL release 1.1.1 or newer.  Users should
 make sure that the most recent OpenSSL patch level is applied.  This release of
-DCMTK is known to compile with OpenSSL releases 1.1.1 as well as 3.0.x to 3.4.x.
+DCMTK is known to compile with OpenSSL releases 1.1.1 as well as 3.0.x to 3.6.x.
 
 When using CMake, if support for security enhancements is desired, a compiled
 version of the OpenSSL libraries and include files must be available during
@@ -244,7 +245,7 @@ Libtiff Support
 
 DCMTK supports the conversion of DICOM images to TIFF.  DCMTK relies on the
 libtiff toolkit (www.libtiff.org) for this purpose.  This release of DCMTK is
-known to compile with libtiff releases 4.5.0 to 4.7.0, although other releases
+known to compile with libtiff release 4.7.1, although other releases
 may work as well.
 
 When using CMake, a compiled version of the libtiff libraries and include files
@@ -256,7 +257,7 @@ Libpng Support
 
 DCMTK supports the conversion of DICOM images to PNG.  DCMTK relies on the
 libpng toolkit (www.libpng.org) for this purpose.  This release of DCMTK is
-known to compile with libpng releases 1.6.39 to 1.6.44, although other releases
+known to compile with libpng releases 1.6.47 to 1.6.51, although other releases
 may work as well.
 
 When using CMake, a compiled version of the libpng libraries and include files
@@ -268,7 +269,7 @@ Libxml2 Support
 
 DCMTK supports the conversion of XML documents to DICOM files.  DCMTK relies on
 the libxml2 toolkit (www.libxml.org) for this purpose.  This release of DCMTK
-is known to compile with libxml2 releases 2.9.14 to 2.13.4, although other
+is known to compile with libxml2 releases 2.13.9 to 2.15.1, although other
 releases may work as well.
 
 When using CMake, if support for XML import is desired, a compiled version of
@@ -396,13 +397,16 @@ variable "CMAKE_CXX_STANDARD".
 By default, DCMTK will compile with "CMAKE_CXX_STANDARD" set to "11" (CXX11).
 The user can choose to build with a newer C++ standard by setting
 "CMAKE_CXX_STANDARD" accordingly.  The following versions are supported:
+
 - 11 (CXX11)
 - 14 (CXX14)
 - 17 (CXX17)
 - 20 (CXX20)
 
-DCMTK will still compile with "CMAKE_CXX_STANDARD" set to "98" (CXX98), but
-support will be removed in future versions of DCMTK.
+Compilation of DCMTK with C++98 is deprecated.  In this release, it can be
+enabled by setting "CMAKE_CXX_STANDARD=98" and "DCMTK_PERMIT_CXX98=ON", but
+support for C++ releases before C++11 will be removed in future versions
+of DCMTK.
 
 Using C++11 or later will change some parts of DCMTK's API, so a C++11 build of
 DCMTK is potentially incompatible with a classic (C++98) build of DCMTK.  This
@@ -431,8 +435,8 @@ directories.  In detail, these "CMakeLists.txt" files will serve as an input to
 CMake which will generate suitable build files for all of DCMTK's projects from
 these files.
 
-DCMTK 3.6.9 requires CMake version 3.7.0 or later.  We recommend using the
-latest stable release of CMake (currently version 3.31.2) since newer versions
+DCMTK 3.7.0 requires CMake version 3.7.0 or later.  We recommend using the
+latest stable release of CMake (currently version 4.2.0) since newer versions
 of CMake often provide better output in case of errors and are generally easier
 to use (for example, by providing better support for detecting the availability
 of third-party libraries).  If possible, use the CMake version your operating
@@ -532,7 +536,7 @@ Through CMake, perform the following steps:
 1. Go to Start -> Programs -> CMake -> "CMake" or "CMake (cmake-gui)" to start
    the CMake utility through which the configuration can be done.
 2. In the entry field "Where is the source code:" enter the directory in which
-   the DCMTK source code resides, e.g. "C:\dcmtk-3.6.9".
+   the DCMTK source code resides, e.g. "C:\dcmtk-3.7.0".
 3. In the entry field "Where to build the binaries:" enter the directory in
    which the libraries and binaries are to be built, e.g. "C:\dcmtk-msvc16".
 4. In the combobox "Build for:" or "Specify the generator for this project:"
@@ -546,43 +550,38 @@ Through CMake, perform the following steps:
    example, in order to turn on libxml2 support, set the value of variable
    "DCMTK_WITH_XML" to "ON" and set the value of variable "WITH_LIBXMLINC" to
    the path where the include files and libraries of libxml2 can be found, e.g.
-   "C:\libxml2-2.13.4".  The support of all other external libraries can be
+   "C:\libxml2-2.15.1".  The support of all other external libraries can be
    turned on in a similar way:
 
      libpng support:
        set "DCMTK_WITH_PNG" to "ON" and
-       set "WITH_LIBPNGINC" e.g. to "C:\libpng-1.6.44"
+       set "WITH_LIBPNGINC" e.g. to "C:\libpng-1.6.51"
 
      libtiff support:
        set "DCMTK_WITH_TIFF" to "ON" and
-       set "WITH_LIBTIFFINC" e.g. to "C:\libtiff-4.7.0"
+       set "WITH_LIBTIFFINC" e.g. to "C:\libtiff-4.7.1"
 
      OpenSSL support:
        set "DCMTK_WITH_OPENSSL" to "ON" and
-       set "WITH_OPENSSLINC" e.g. to "C:\openssl-3.4.0"
+       set "WITH_OPENSSLINC" e.g. to "C:\openssl-3.6.0"
 
      zlib support:
        set "DCMTK_WITH_ZLIB" to "ON" and
        set "WITH_ZLIBINC" e.g. to "C:\zlib-1.3.1"
 
-     libiconv support:
-       set "DCMTK_WITH_ICONV" to "ON" and
-       set "WITH_LIBICONVINC" e.g. to "C:\libiconv-1.17"
-
    In order to turn the support of a certain external library off, set the
    value of the corresponding variable ("DCMTK_WITH_XML", "DCMTK_WITH_PNG",
-   "DCMTK_WITH_TIFF", "DCMTK_WITH_OPENSSL", "DCMTK_WITH_ZLIB" or
-   "DCMTK_WITH_ICONV") to "OFF".
+   "DCMTK_WITH_TIFF", "DCMTK_WITH_OPENSSL" or "DCMTK_WITH_ZLIB") to "OFF".
 
    (Please note that the include files of all external libraries are always
    expected in a directory named "include" below the directory that is
    specified in "WITH_LIBXMLINC", "WITH_LIBPNGINC", "WITH_LIBTIFFINC",
-   "WITH_OPENSSLINC", "WITH_ZLIBINC" or "WITH_LIBICONVINC".)
+   "WITH_OPENSSLINC" or "WITH_ZLIBINC".)
 
    (Please note also that the library files of all external libraries are always
    expected in directory named "lib" below the directory that is specified in
-   "WITH_LIBXMLINC", "WITH_LIBPNGINC", "WITH_LIBTIFFINC", "WITH_OPENSSLINC",
-   "WITH_ZLIBINC" or "WITH_LIBICONV".  Moreover, note that the following
+   "WITH_LIBXMLINC", "WITH_LIBPNGINC", "WITH_LIBTIFFINC", "WITH_OPENSSLINC"
+   or "WITH_ZLIBINC".  Moreover, note that the following
    filenames must be used for the corresponding lib files:
 
      libxml2:
@@ -609,21 +608,16 @@ Through CMake, perform the following steps:
        "zlib_d.lib"        - debug version
        "zlib_o.lib"        - release version (optimized)
 
-     libiconv: (* See note below)
-       "libiconv_d.lib"    - debug version
-       "libiconv_o.lib"    - release version (optimized)
-       "libchset_d.lib"    - debug version
-       "libchset_o.lib"    - release version (optimized)
+   The debug and release versions of all libraries must be compiled with the
+   same runtime library dependency as DCMTK (i.e., /MT[d] or /MD[d]).
+   By default, DCMTK is compiled with /MTd for Debug and /MT for Release mode
+   unless the CMake variables "DCMTK_COMPILE_WIN32_MULTITHREADED_DLL" or
+   "BUILD_SHARED_LIBS" (see below) are set to true, in which case DCMTK is
+   compiled with /MDd for Debug and /MD for Release mode.
 
-   The debug versions of all libraries must be compiled for the multithread
-   debug version of the runtime (/MTd), the release version must be compiled
-   for the non-debug multithread runtime (/MT).  Precompiled versions of all
-   libraries (*) can be downloaded from https://dcmtk.org/develop/#lib-win .
+   Precompiled versions of all libraries can be downloaded from
+   https://dcmtk.org/develop/#lib-win .
 
-   (*) Starting with DCMTK 3.6.8, libiconv is no longer part of the download
-       package.  That also means that libxml2 was built without this library.
-       Therefore, DCMTK tools that read XML files will only support UTF-8 and
-       Latin-1 encoding.
 
    In the CMake GUI, there are a few more settings that can be modified
    to affect the way DCMTK is compiled.  The most important of these are:
@@ -698,28 +692,28 @@ see: https://cmake.org/cmake/help/latest/module/FindZLIB.html .
 The typical way to build DCMTK on Unix-like systems with CMake is as follows
 (if not using the GUI, in that case look at the description for Windows above):
 
-    mkdir dcmtk-3.6.9-build
-    cd dcmtk-3.6.9-build
-    cmake ../dcmtk-3.6.9
+    mkdir dcmtk-3.7.0-build
+    cd dcmtk-3.7.0-build
+    cmake ../dcmtk-3.7.0
     make -j8
-    make DESTDIR=../dcmtk-3.6.9-install install
+    make DESTDIR=../dcmtk-3.7.0-install install
 
 The above commands assume that the DCMTK source code was extracted to the
-current working directory into a folder named "dcmtk-3.6.9".  DCMTK will be
+current working directory into a folder named "dcmtk-3.7.0".  DCMTK will be
 configured using CMake with the default options, detecting and including all
 available support libraries and then compiled using eight CPU cores
 ("make -j8", adjust as needed).  The result will be installed to the directory
-"dcmtk-3.6.9-install" next to the source code directory.
+"dcmtk-3.7.0-install" next to the source code directory.
 
 If you want to modify your build configuration, like enabling or disabling some
 features of DCMTK (e.g. PNG support), or if you need to modify the predefined
 build variables, you can use the curses-based CMake configuration tool ccmake.
 First, create the initial build setup (system check) and then call "ccmake":
 
-    mkdir dcmtk-3.6.9-build
-    cd dcmtk-3.6.9-build
-    cmake ../dcmtk-3.6.9
-    ccmake ../dcmtk-3.6.9
+    mkdir dcmtk-3.7.0-build
+    cd dcmtk-3.7.0-build
+    cmake ../dcmtk-3.7.0
+    ccmake ../dcmtk-3.7.0
 
 Now you can modify the configuration values.  Please see the help on the bottom
 of the screen.  When finished, press "c" to generate a new build configuration,
@@ -729,9 +723,9 @@ If you already know the variable names, types and values to set, you can skip
 the ccmake step above and call "cmake" directly with the desired values set.
 Example for a build with TCP wrapper disabled:
 
-    mkdir dcmtk-3.6.9-build
-    cd dcmtk-3.6.9-build
-    cmake -DDCMTK_WITH_WRAP:BOOL=FALSE ../dcmtk-3.6.9
+    mkdir dcmtk-3.7.0-build
+    cd dcmtk-3.7.0-build
+    cmake -DDCMTK_WITH_WRAP:BOOL=FALSE ../dcmtk-3.7.0
     ...
 
 The format is "NAME:TYPE=VALUE".  Use ccmake to find out the variable names and
@@ -759,7 +753,7 @@ HTML DOCUMENTATION AND MAN PAGES
 Most DCMTK modules have been documented with Doxygen (www.doxygen.org), a free
 source code documentation system similar to Javadoc.  Unix users who have
 Doxygen installed can create a hypertext documentation with "make html" in the
-"dcmtk-3.6.9" or "doxygen" directory; Windows and other CMake users should
+"dcmtk-3.7.0" or "doxygen" directory; Windows and other CMake users should
 build the "DOXYGEN" target.  A project file for Microsoft's HTML Help Workshop
 can also be generated allowing to create a single CHM file (compressed HTML)
 from the documentation.  Other output formats (e.g. LaTeX) can be enabled by
@@ -900,7 +894,7 @@ removed in a future release.  In the current release, the "configure" script in
 DCMTK's top-level main directory has been removed as the final warning for users
 of the Autoconf toolchain.  If you prefer to build DCMTK with Autoconf, however,
 this is still possible.  Perform the following steps from the top-level
-("dcmtk-3.6.9") directory to compile and install the software:
+("dcmtk-3.7.0") directory to compile and install the software:
 
 Step 0:
     cd config
@@ -930,14 +924,14 @@ which OpenSSL is installed.  This is usually the directory that has been used as
 "--prefix" when compiling and installing OpenSSL.
 
 For example, if you wish to enable the security enhancements, and OpenSSL is
-installed in "/usr/local/apps/openssl-3.4.0", you should start configure as:
+installed in "/usr/local/apps/openssl-3.6.0", you should start configure as:
 
     ./configure --ignore-deprecation
-                --with-opensslinc=/usr/local/apps/openssl-3.4.0
+                --with-opensslinc=/usr/local/apps/openssl-3.6.0
 
 Configure will assume that the OpenSSL include files are installed in
-"/usr/local/apps/openssl-3.4.0/include" and will expect the library in
-"/usr/local/apps/openssl-3.4.0/lib".  Appropriate options will be passed to
+"/usr/local/apps/openssl-3.6.0/include" and will expect the library in
+"/usr/local/apps/openssl-3.6.0/lib".  Appropriate options will be passed to
 the compiler and the linker.
 
 Support for zlib, libtiff, libpng, libxml2, libwrap, and/or libiconv can be
@@ -946,9 +940,9 @@ standard path), e.g.:
 
     ./configure --ignore-deprecation
                 --with-libzlibinc=/usr/local/apps/zlib-1.3.1
-                --with-libtiffinc=/usr/local/apps/libtiff-4.7.0
-                --with-libpnginc=/usr/local/apps/libpng-1.6.44
-                --with-libxmlinc=/usr/local/apps/libxml2-2.13.4
+                --with-libtiffinc=/usr/local/apps/libtiff-4.7.1
+                --with-libpnginc=/usr/local/apps/libpng-1.6.51
+                --with-libxmlinc=/usr/local/apps/libxml2-2.15.1
                 --with-libwrapinc=/usr/local/apps/tcp_wrappers-7.6
                 --with-libiconvinc=/usr/local/apps/libiconv-1.17
 
@@ -1047,7 +1041,7 @@ See also the FAQ at https://forum.dcmtk.org/faq for more hints.
 
 Have fun.
 
-M. Eichelberg, J. Riesmeier, M. Onken, T. Xu
+M. Eichelberg, J. Riesmeier, M. Onken, T. Xu, H. Roesen
 DCMTK Development Team, Oldenburg, Germany.
 
-Last revised: 2024-12-10 (Onken)
+Last revised: 2025-12-02 (Riesmeier)
index 44ef8d37b2a2a7b8993e67ffbe5ab48a2f33079f..416c12523796f9d349bee4eacc28f8c75a4fd3d4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,39 +9,39 @@ include $(configdir)/Makefile.def
 
 .NOTPARALLEL:
 
-all:  config-all oficonv-all ofstd-all oflog-all dcmdata-all dcmiod-all dcmfg-all dcmseg-all dcmimgle-all dcmimage-all dcmjpeg-all dcmjpls-all dcmtls-all dcmnet-all dcmsr-all dcmsign-all dcmwlm-all dcmqrdb-all dcmpstat-all dcmrt-all dcmtract-all dcmpmap-all dcmect-all dcmapps-all
+all:  config-all oficonv-all ofstd-all oflog-all dcmdata-all dcmimgle-all dcmimage-all dcmjpeg-all dcmjpls-all dcmtls-all dcmnet-all dcmsr-all dcmsign-all dcmwlm-all dcmqrdb-all dcmrt-all dcmiod-all dcmpstat-all dcmfg-all dcmseg-all dcmtract-all dcmpmap-all dcmect-all dcmapps-all
 
-libsrc-all:  oficonv-libsrc-all ofstd-libsrc-all oflog-libsrc-all dcmdata-libsrc-all dcmiod-libsrc-all dcmfg-libsrc-all dcmseg-libsrc-all dcmimgle-libsrc-all dcmimage-libsrc-all dcmjpeg-libsrc-all dcmjpls-libsrc-all dcmtls-libsrc-all dcmnet-libsrc-all dcmsr-libsrc-all dcmsign-libsrc-all dcmwlm-libsrc-all dcmqrdb-libsrc-all dcmpstat-libsrc-all dcmrt-libsrc-all dcmtract-libsrc-all dcmpmap-libsrc-all dcmect-libsrc-all dcmapps-libsrc-all
+libsrc-all:  oficonv-libsrc-all ofstd-libsrc-all oflog-libsrc-all dcmdata-libsrc-all dcmimgle-libsrc-all dcmimage-libsrc-all dcmjpeg-libsrc-all dcmjpls-libsrc-all dcmtls-libsrc-all dcmnet-libsrc-all dcmsr-libsrc-all dcmsign-libsrc-all dcmwlm-libsrc-all dcmqrdb-libsrc-all dcmrt-libsrc-all dcmiod-libsrc-all dcmpstat-libsrc-all dcmfg-libsrc-all dcmseg-libsrc-all dcmtract-libsrc-all dcmpmap-libsrc-all dcmect-libsrc-all dcmapps-libsrc-all
 
-tests-all:  config-tests-all oficonv-tests-all ofstd-tests-all oflog-tests-all dcmdata-tests-all dcmiod-tests-all dcmfg-tests-all dcmseg-tests-all dcmimgle-tests-all dcmimage-tests-all dcmjpeg-tests-all dcmjpls-tests-all dcmtls-tests-all dcmnet-tests-all dcmsr-tests-all dcmsign-tests-all dcmwlm-tests-all dcmqrdb-tests-all dcmpstat-tests-all dcmrt-tests-all dcmtract-tests-all dcmpmap-tests-all dcmect-tests-all dcmapps-tests-all
+tests-all:  config-tests-all oficonv-tests-all ofstd-tests-all oflog-tests-all dcmdata-tests-all dcmimgle-tests-all dcmimage-tests-all dcmjpeg-tests-all dcmjpls-tests-all dcmtls-tests-all dcmnet-tests-all dcmsr-tests-all dcmsign-tests-all dcmwlm-tests-all dcmqrdb-tests-all dcmrt-tests-all dcmiod-tests-all dcmpstat-tests-all dcmfg-tests-all dcmseg-tests-all dcmtract-tests-all dcmpmap-tests-all dcmect-tests-all dcmapps-tests-all
 
-install:  config-install oficonv-install ofstd-install oflog-install dcmdata-install dcmiod-install dcmfg-install dcmseg-install dcmimgle-install dcmimage-install dcmjpeg-install dcmjpls-install dcmtls-install dcmnet-install dcmsr-install dcmsign-install dcmwlm-install dcmqrdb-install dcmpstat-install dcmrt-install dcmtract-install dcmpmap-install dcmect-install dcmapps-install dcmtk-install-doc install-man
+install:  config-install oficonv-install ofstd-install oflog-install dcmdata-install dcmimgle-install dcmimage-install dcmjpeg-install dcmjpls-install dcmtls-install dcmnet-install dcmsr-install dcmsign-install dcmwlm-install dcmqrdb-install dcmrt-install dcmiod-install dcmpstat-install dcmfg-install dcmseg-install dcmtract-install dcmpmap-install dcmect-install dcmapps-install dcmtk-install-doc install-man
 
 install-all: install install-lib install-html
 
-install-bin:  config-install-bin oficonv-install-bin ofstd-install-bin oflog-install-bin dcmdata-install-bin dcmiod-install-bin dcmfg-install-bin dcmseg-install-bin dcmimgle-install-bin dcmimage-install-bin dcmjpeg-install-bin dcmjpls-install-bin dcmtls-install-bin dcmnet-install-bin dcmsr-install-bin dcmsign-install-bin dcmwlm-install-bin dcmqrdb-install-bin dcmpstat-install-bin dcmrt-install-bin dcmtract-install-bin dcmpmap-install-bin dcmect-install-bin dcmapps-install-bin
+install-bin:  config-install-bin oficonv-install-bin ofstd-install-bin oflog-install-bin dcmdata-install-bin dcmimgle-install-bin dcmimage-install-bin dcmjpeg-install-bin dcmjpls-install-bin dcmtls-install-bin dcmnet-install-bin dcmsr-install-bin dcmsign-install-bin dcmwlm-install-bin dcmqrdb-install-bin dcmrt-install-bin dcmiod-install-bin dcmpstat-install-bin dcmfg-install-bin dcmseg-install-bin dcmtract-install-bin dcmpmap-install-bin dcmect-install-bin dcmapps-install-bin
 
-install-doc:  config-install-doc oficonv-install-doc ofstd-install-doc oflog-install-doc dcmdata-install-doc dcmiod-install-doc dcmfg-install-doc dcmseg-install-doc dcmimgle-install-doc dcmimage-install-doc dcmjpeg-install-doc dcmjpls-install-doc dcmtls-install-doc dcmnet-install-doc dcmsr-install-doc dcmsign-install-doc dcmwlm-install-doc dcmqrdb-install-doc dcmpstat-install-doc dcmrt-install-doc dcmtract-install-doc dcmpmap-install-doc dcmect-install-doc dcmapps-install-doc
+install-doc:  config-install-doc oficonv-install-doc ofstd-install-doc oflog-install-doc dcmdata-install-doc dcmimgle-install-doc dcmimage-install-doc dcmjpeg-install-doc dcmjpls-install-doc dcmtls-install-doc dcmnet-install-doc dcmsr-install-doc dcmsign-install-doc dcmwlm-install-doc dcmqrdb-install-doc dcmrt-install-doc dcmiod-install-doc dcmpstat-install-doc dcmfg-install-doc dcmseg-install-doc dcmtract-install-doc dcmpmap-install-doc dcmect-install-doc dcmapps-install-doc
 
-install-data:  config-install-data oficonv-install-data ofstd-install-data oflog-install-data dcmdata-install-data dcmiod-install-data dcmfg-install-data dcmseg-install-data dcmimgle-install-data dcmimage-install-data dcmjpeg-install-data dcmjpls-install-data dcmtls-install-data dcmnet-install-data dcmsr-install-data dcmsign-install-data dcmwlm-install-data dcmqrdb-install-data dcmpstat-install-data dcmrt-install-data dcmtract-install-data dcmpmap-install-data dcmect-install-data dcmapps-install-data
+install-data:  config-install-data oficonv-install-data ofstd-install-data oflog-install-data dcmdata-install-data dcmimgle-install-data dcmimage-install-data dcmjpeg-install-data dcmjpls-install-data dcmtls-install-data dcmnet-install-data dcmsr-install-data dcmsign-install-data dcmwlm-install-data dcmqrdb-install-data dcmrt-install-data dcmiod-install-data dcmpstat-install-data dcmfg-install-data dcmseg-install-data dcmtract-install-data dcmpmap-install-data dcmect-install-data dcmapps-install-data
 
-install-etc:  config-install-etc oficonv-install-etc ofstd-install-etc oflog-install-etc dcmdata-install-etc dcmiod-install-etc dcmfg-install-etc dcmseg-install-etc dcmimgle-install-etc dcmimage-install-etc dcmjpeg-install-etc dcmjpls-install-etc dcmtls-install-etc dcmnet-install-etc dcmsr-install-etc dcmsign-install-etc dcmwlm-install-etc dcmqrdb-install-etc dcmpstat-install-etc dcmrt-install-etc dcmtract-install-etc dcmpmap-install-etc dcmect-install-etc dcmapps-install-etc
+install-etc:  config-install-etc oficonv-install-etc ofstd-install-etc oflog-install-etc dcmdata-install-etc dcmimgle-install-etc dcmimage-install-etc dcmjpeg-install-etc dcmjpls-install-etc dcmtls-install-etc dcmnet-install-etc dcmsr-install-etc dcmsign-install-etc dcmwlm-install-etc dcmqrdb-install-etc dcmrt-install-etc dcmiod-install-etc dcmpstat-install-etc dcmfg-install-etc dcmseg-install-etc dcmtract-install-etc dcmpmap-install-etc dcmect-install-etc dcmapps-install-etc
 
-install-lib:  config-install-lib oficonv-install-lib ofstd-install-lib oflog-install-lib dcmdata-install-lib dcmiod-install-lib dcmfg-install-lib dcmseg-install-lib dcmimgle-install-lib dcmimage-install-lib dcmjpeg-install-lib dcmjpls-install-lib dcmtls-install-lib dcmnet-install-lib dcmsr-install-lib dcmsign-install-lib dcmwlm-install-lib dcmqrdb-install-lib dcmpstat-install-lib dcmrt-install-lib dcmtract-install-lib dcmpmap-install-lib dcmect-install-lib dcmapps-install-lib
+install-lib:  config-install-lib oficonv-install-lib ofstd-install-lib oflog-install-lib dcmdata-install-lib dcmimgle-install-lib dcmimage-install-lib dcmjpeg-install-lib dcmjpls-install-lib dcmtls-install-lib dcmnet-install-lib dcmsr-install-lib dcmsign-install-lib dcmwlm-install-lib dcmqrdb-install-lib dcmrt-install-lib dcmiod-install-lib dcmpstat-install-lib dcmfg-install-lib dcmseg-install-lib dcmtract-install-lib dcmpmap-install-lib dcmect-install-lib dcmapps-install-lib
 
-install-include:  config-install-include oficonv-install-include ofstd-install-include oflog-install-include dcmdata-install-include dcmiod-install-include dcmfg-install-include dcmseg-install-include dcmimgle-install-include dcmimage-install-include dcmjpeg-install-include dcmjpls-install-include dcmtls-install-include dcmnet-install-include dcmsr-install-include dcmsign-install-include dcmwlm-install-include dcmqrdb-install-include dcmpstat-install-include dcmrt-install-include dcmtract-install-include dcmpmap-install-include dcmect-install-include dcmapps-install-include
+install-include:  config-install-include oficonv-install-include ofstd-install-include oflog-install-include dcmdata-install-include dcmimgle-install-include dcmimage-install-include dcmjpeg-install-include dcmjpls-install-include dcmtls-install-include dcmnet-install-include dcmsr-install-include dcmsign-install-include dcmwlm-install-include dcmqrdb-install-include dcmrt-install-include dcmiod-install-include dcmpstat-install-include dcmfg-install-include dcmseg-install-include dcmtract-install-include dcmpmap-install-include dcmect-install-include dcmapps-install-include
 
-install-support:  config-install-support oficonv-install-support ofstd-install-support oflog-install-support dcmdata-install-support dcmiod-install-support dcmfg-install-support dcmseg-install-support dcmimgle-install-support dcmimage-install-support dcmjpeg-install-support dcmjpls-install-support dcmtls-install-support dcmnet-install-support dcmsr-install-support dcmsign-install-support dcmwlm-install-support dcmqrdb-install-support dcmpstat-install-support dcmrt-install-support dcmtract-install-support dcmpmap-install-support dcmect-install-support dcmapps-install-support
+install-support:  config-install-support oficonv-install-support ofstd-install-support oflog-install-support dcmdata-install-support dcmimgle-install-support dcmimage-install-support dcmjpeg-install-support dcmjpls-install-support dcmtls-install-support dcmnet-install-support dcmsr-install-support dcmsign-install-support dcmwlm-install-support dcmqrdb-install-support dcmrt-install-support dcmiod-install-support dcmpstat-install-support dcmfg-install-support dcmseg-install-support dcmtract-install-support dcmpmap-install-support dcmect-install-support dcmapps-install-support
 
 check: tests-all
        $(MAKE) -s check-nosilent
 
-check-nosilent:  config-check oficonv-check ofstd-check oflog-check dcmdata-check dcmiod-check dcmfg-check dcmseg-check dcmimgle-check dcmimage-check dcmjpeg-check dcmjpls-check dcmtls-check dcmnet-check dcmsr-check dcmsign-check dcmwlm-check dcmqrdb-check dcmpstat-check dcmrt-check dcmtract-check dcmpmap-check dcmect-check dcmapps-check
+check-nosilent:  config-check oficonv-check ofstd-check oflog-check dcmdata-check dcmimgle-check dcmimage-check dcmjpeg-check dcmjpls-check dcmtls-check dcmnet-check dcmsr-check dcmsign-check dcmwlm-check dcmqrdb-check dcmrt-check dcmiod-check dcmpstat-check dcmfg-check dcmseg-check dcmtract-check dcmpmap-check dcmect-check dcmapps-check
 
 check-exhaustive: tests-all
        $(MAKE) -s check-nosilent-exhaustive
 
-check-nosilent-exhaustive:  config-check-exhaustive oficonv-check-exhaustive ofstd-check-exhaustive oflog-check-exhaustive dcmdata-check-exhaustive dcmiod-check-exhaustive dcmfg-check-exhaustive dcmseg-check-exhaustive dcmimgle-check-exhaustive dcmimage-check-exhaustive dcmjpeg-check-exhaustive dcmjpls-check-exhaustive dcmtls-check-exhaustive dcmnet-check-exhaustive dcmsr-check-exhaustive dcmsign-check-exhaustive dcmwlm-check-exhaustive dcmqrdb-check-exhaustive dcmpstat-check-exhaustive dcmrt-check-exhaustive dcmtract-check-exhaustive dcmpmap-check-exhaustive dcmect-check-exhaustive dcmapps-check-exhaustive
+check-nosilent-exhaustive:  config-check-exhaustive oficonv-check-exhaustive ofstd-check-exhaustive oflog-check-exhaustive dcmdata-check-exhaustive dcmimgle-check-exhaustive dcmimage-check-exhaustive dcmjpeg-check-exhaustive dcmjpls-check-exhaustive dcmtls-check-exhaustive dcmnet-check-exhaustive dcmsr-check-exhaustive dcmsign-check-exhaustive dcmwlm-check-exhaustive dcmqrdb-check-exhaustive dcmrt-check-exhaustive dcmiod-check-exhaustive dcmpstat-check-exhaustive dcmfg-check-exhaustive dcmseg-check-exhaustive dcmtract-check-exhaustive dcmpmap-check-exhaustive dcmect-check-exhaustive dcmapps-check-exhaustive
 
 dcmtk-install-doc:
        $(configdir)/mkinstalldirs $(DESTDIR)$(docdir)
@@ -91,7 +91,7 @@ help:
        @echo ""
        @echo "The following modules are available:"
        @echo ""
-       @echo "oficonv ofstd oflog dcmdata dcmiod dcmfg dcmseg dcmimgle dcmimage dcmjpeg dcmjpls dcmtls dcmnet dcmsr dcmsign dcmwlm dcmqrdb dcmpstat dcmrt dcmtract dcmpmap dcmect dcmapps"
+       @echo "oficonv ofstd oflog dcmdata dcmimgle dcmimage dcmjpeg dcmjpls dcmtls dcmnet dcmsr dcmsign dcmwlm dcmqrdb dcmrt dcmiod dcmpstat dcmfg dcmseg dcmtract dcmpmap dcmect dcmapps"
 
 config-all:
        (cd config && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
@@ -288,123 +288,6 @@ dcmdata-check:
 dcmdata-check-exhaustive:
        (cd dcmdata && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
 
-dcmiod-all:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
-
-dcmiod-libsrc-all:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
-
-dcmiod-tests-all:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
-
-dcmiod-install:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
-
-dcmiod-install-bin:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
-
-dcmiod-install-doc:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
-
-dcmiod-install-data:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
-
-dcmiod-install-etc:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
-
-dcmiod-install-lib:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
-
-dcmiod-install-include:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
-
-dcmiod-install-support:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
-
-dcmiod-check:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
-
-dcmiod-check-exhaustive:
-       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
-
-dcmfg-all:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
-
-dcmfg-libsrc-all:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
-
-dcmfg-tests-all:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
-
-dcmfg-install:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
-
-dcmfg-install-bin:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
-
-dcmfg-install-doc:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
-
-dcmfg-install-data:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
-
-dcmfg-install-etc:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
-
-dcmfg-install-lib:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
-
-dcmfg-install-include:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
-
-dcmfg-install-support:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
-
-dcmfg-check:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
-
-dcmfg-check-exhaustive:
-       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
-
-dcmseg-all:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
-
-dcmseg-libsrc-all:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
-
-dcmseg-tests-all:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
-
-dcmseg-install:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
-
-dcmseg-install-bin:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
-
-dcmseg-install-doc:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
-
-dcmseg-install-data:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
-
-dcmseg-install-etc:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
-
-dcmseg-install-lib:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
-
-dcmseg-install-include:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
-
-dcmseg-install-support:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
-
-dcmseg-check:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
-
-dcmseg-check-exhaustive:
-       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
-
 dcmimgle-all:
        (cd dcmimgle && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
 
@@ -795,6 +678,84 @@ dcmqrdb-check:
 dcmqrdb-check-exhaustive:
        (cd dcmqrdb && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
 
+dcmrt-all:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
+
+dcmrt-libsrc-all:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
+
+dcmrt-tests-all:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
+
+dcmrt-install:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
+
+dcmrt-install-bin:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
+
+dcmrt-install-doc:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
+
+dcmrt-install-data:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
+
+dcmrt-install-etc:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
+
+dcmrt-install-lib:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
+
+dcmrt-install-include:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
+
+dcmrt-install-support:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
+
+dcmrt-check:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
+
+dcmrt-check-exhaustive:
+       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
+
+dcmiod-all:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
+
+dcmiod-libsrc-all:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
+
+dcmiod-tests-all:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
+
+dcmiod-install:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
+
+dcmiod-install-bin:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
+
+dcmiod-install-doc:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
+
+dcmiod-install-data:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
+
+dcmiod-install-etc:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
+
+dcmiod-install-lib:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
+
+dcmiod-install-include:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
+
+dcmiod-install-support:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
+
+dcmiod-check:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
+
+dcmiod-check-exhaustive:
+       (cd dcmiod && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
+
 dcmpstat-all:
        (cd dcmpstat && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
 
@@ -834,44 +795,83 @@ dcmpstat-check:
 dcmpstat-check-exhaustive:
        (cd dcmpstat && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
 
-dcmrt-all:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
+dcmfg-all:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
 
-dcmrt-libsrc-all:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
+dcmfg-libsrc-all:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
 
-dcmrt-tests-all:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
+dcmfg-tests-all:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
 
-dcmrt-install:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
+dcmfg-install:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
 
-dcmrt-install-bin:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
+dcmfg-install-bin:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
 
-dcmrt-install-doc:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
+dcmfg-install-doc:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
 
-dcmrt-install-data:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
+dcmfg-install-data:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
 
-dcmrt-install-etc:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
+dcmfg-install-etc:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
 
-dcmrt-install-lib:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
+dcmfg-install-lib:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
 
-dcmrt-install-include:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
+dcmfg-install-include:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
 
-dcmrt-install-support:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
+dcmfg-install-support:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
 
-dcmrt-check:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
+dcmfg-check:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
 
-dcmrt-check-exhaustive:
-       (cd dcmrt && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
+dcmfg-check-exhaustive:
+       (cd dcmfg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
+
+dcmseg-all:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
+
+dcmseg-libsrc-all:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" libsrc-all)
+
+dcmseg-tests-all:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" tests-all)
+
+dcmseg-install:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install)
+
+dcmseg-install-bin:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-bin)
+
+dcmseg-install-doc:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-doc)
+
+dcmseg-install-data:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-data)
+
+dcmseg-install-etc:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-etc)
+
+dcmseg-install-lib:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-lib)
+
+dcmseg-install-include:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-include)
+
+dcmseg-install-support:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" install-support)
+
+dcmseg-check:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check)
+
+dcmseg-check-exhaustive:
+       (cd dcmseg && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" check-exhaustive)
 
 dcmtract-all:
        (cd dcmtract && $(MAKE) ARCH="$(ARCH)" DESTDIR="$(DESTDIR)" all)
@@ -1035,9 +1035,6 @@ dependencies:
        (cd ofstd && $(MAKE) dependencies)
        (cd oflog && $(MAKE) dependencies)
        (cd dcmdata && $(MAKE) dependencies)
-       (cd dcmiod && $(MAKE) dependencies)
-       (cd dcmfg && $(MAKE) dependencies)
-       (cd dcmseg && $(MAKE) dependencies)
        (cd dcmimgle && $(MAKE) dependencies)
        (cd dcmimage && $(MAKE) dependencies)
        (cd dcmjpeg && $(MAKE) dependencies)
@@ -1048,8 +1045,11 @@ dependencies:
        (cd dcmsign && $(MAKE) dependencies)
        (cd dcmwlm && $(MAKE) dependencies)
        (cd dcmqrdb && $(MAKE) dependencies)
-       (cd dcmpstat && $(MAKE) dependencies)
        (cd dcmrt && $(MAKE) dependencies)
+       (cd dcmiod && $(MAKE) dependencies)
+       (cd dcmpstat && $(MAKE) dependencies)
+       (cd dcmfg && $(MAKE) dependencies)
+       (cd dcmseg && $(MAKE) dependencies)
        (cd dcmtract && $(MAKE) dependencies)
        (cd dcmpmap && $(MAKE) dependencies)
        (cd dcmect && $(MAKE) dependencies)
@@ -1060,9 +1060,6 @@ clean:
        (cd ofstd && $(MAKE) clean)
        (cd oflog && $(MAKE) clean)
        (cd dcmdata && $(MAKE) clean)
-       (cd dcmiod && $(MAKE) clean)
-       (cd dcmfg && $(MAKE) clean)
-       (cd dcmseg && $(MAKE) clean)
        (cd dcmimgle && $(MAKE) clean)
        (cd dcmimage && $(MAKE) clean)
        (cd dcmjpeg && $(MAKE) clean)
@@ -1073,8 +1070,11 @@ clean:
        (cd dcmsign && $(MAKE) clean)
        (cd dcmwlm && $(MAKE) clean)
        (cd dcmqrdb && $(MAKE) clean)
-       (cd dcmpstat && $(MAKE) clean)
        (cd dcmrt && $(MAKE) clean)
+       (cd dcmiod && $(MAKE) clean)
+       (cd dcmpstat && $(MAKE) clean)
+       (cd dcmfg && $(MAKE) clean)
+       (cd dcmseg && $(MAKE) clean)
        (cd dcmtract && $(MAKE) clean)
        (cd dcmpmap && $(MAKE) clean)
        (cd dcmect && $(MAKE) clean)
@@ -1088,9 +1088,6 @@ distclean:
        (cd ofstd && $(MAKE) distclean)
        (cd oflog && $(MAKE) distclean)
        (cd dcmdata && $(MAKE) distclean)
-       (cd dcmiod && $(MAKE) distclean)
-       (cd dcmfg && $(MAKE) distclean)
-       (cd dcmseg && $(MAKE) distclean)
        (cd dcmimgle && $(MAKE) distclean)
        (cd dcmimage && $(MAKE) distclean)
        (cd dcmjpeg && $(MAKE) distclean)
@@ -1101,8 +1098,11 @@ distclean:
        (cd dcmsign && $(MAKE) distclean)
        (cd dcmwlm && $(MAKE) distclean)
        (cd dcmqrdb && $(MAKE) distclean)
-       (cd dcmpstat && $(MAKE) distclean)
        (cd dcmrt && $(MAKE) distclean)
+       (cd dcmiod && $(MAKE) distclean)
+       (cd dcmpstat && $(MAKE) distclean)
+       (cd dcmfg && $(MAKE) distclean)
+       (cd dcmseg && $(MAKE) distclean)
        (cd dcmtract && $(MAKE) distclean)
        (cd dcmpmap && $(MAKE) distclean)
        (cd dcmect && $(MAKE) distclean)
diff --git a/VERSION b/VERSION
index cff2619cfb9409b0f202973810ccc91fc1c25fc5..7c69a55dbb18555b0baec9712461a06b0667ae7b 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.6.9
+3.7.0
index 38d2e6c1f16e196352b6d41a68ba92eba3e3d945..ed66314c9a90764720dea90ef4c82f646b42ce12 100644 (file)
@@ -344,30 +344,6 @@ fi
 rm -f conftest*])
 
 
-dnl AC_CHECK_STD_NAMESPACE checks if the C++-Compiler supports the
-dnl   standard name space.
-dnl
-dnl AC_CHECK_STD_NAMESPACE
-AC_DEFUN(AC_CHECK_STD_NAMESPACE,
-[AC_MSG_CHECKING([for C++ standard namespace])
-AH_TEMPLATE(HAVE_STD_NAMESPACE, [Define if ANSI standard C++ includes use std namespace.])
-AC_CACHE_VAL(ac_cv_check_std_namespace,
-[AC_TRY_COMPILE_AND_LINK([
-#include <iostream>
-using namespace std;
-],[
-  cout << "Hello World" << endl;
-], eval "ac_cv_check_std_namespace=yes", eval "ac_cv_check_std_namespace=no")dnl
-])dnl
-if eval "test \"`echo '$ac_cv_check_std_namespace'`\" = yes"; then
-  AC_MSG_RESULT(yes)
-  AC_DEFINE(HAVE_STD_NAMESPACE)
-else
-  AC_MSG_RESULT(no)
-fi
-])
-
-
 dnl AC_CHECK_GNU_LIBTOOL checks whether libtool is GNU libtool.
 dnl   This macro requires that 'libtool' exists in the current path,
 dnl   i.e. AC_CHECK_PROGS(LIBTOOL, libtool, :) should be executed and evaluated
@@ -514,75 +490,6 @@ fi
 ])
 
 
-dnl AC_CHECK_INTP_ACCEPT checks if the prototype for accept()
-dnl   specifies arguments 2-4 to be int* instead of size_t *.
-dnl
-dnl AC_CHECK_INTP_ACCEPT(HEADER-FILE..., ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
-AC_DEFUN(AC_CHECK_INTP_ACCEPT,
-[AC_MSG_CHECKING([ifelse([$1], , [if accept() needs int* parameters],
-[if accept() needs int* parameters (in $1)])])
-AH_TEMPLATE(HAVE_INTP_ACCEPT, [Define if your system declares argument 3 of accept()
-   as int * instead of size_t * or socklen_t *.])
-ifelse([$1], , [ac_includes=""
-],
-[ac_includes=""
-for ac_header in $1
-do
-  ac_includes="$ac_includes
-#include<$ac_header>"
-done])
-AC_CACHE_VAL(ac_cv_prototype_intp_accept,
-[AC_TRY_COMPILE(
-[#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-]
-,
-[
-  int i;
-  struct sockaddr *addr;
-  size_t addrlen;
-
-  addr = 0;
-  addrlen = 0;
-  i = accept(1, addr, &addrlen);
-],
-eval "ac_cv_prototype_intp_accept=no",
-[AC_TRY_COMPILE(
-[#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-]
-,
-[
-  int i;
-  struct sockaddr *addr;
-  int addrlen;
-
-  addr = 0;
-  addrlen = 0;
-  i = accept(1, addr, &addrlen);
-],
-eval "ac_cv_prototype_intp_accept=yes", eval "ac_cv_prototype_intp_accept=no")])])
-if eval "test \"`echo $ac_cv_prototype_intp_accept`\" = yes"; then
-  AC_MSG_RESULT(yes)
-  AC_DEFINE(HAVE_INTP_ACCEPT)
-  ifelse([$2], , :, [$2])
-else
-  AC_MSG_RESULT(no)
-  ifelse([$3], , , [$3])
-fi
-])
-
-
 dnl AC_CHECK_PTHREAD_OPTION checks whether the compiler requires the
 dnl -pthread option to correctly link code containing posix thread calls.
 dnl This is true for example on FreeBSD.
@@ -680,105 +587,6 @@ fi
 ])
 
 
-dnl AC_CHECK_INTP_GETSOCKOPT checks if the prototype for getsockopt()
-dnl   specifies arguments 5 to be int* instead of size_t *.
-dnl
-dnl AC_CHECK_INTP_GETSOCKOPT(HEADER-FILE..., ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
-AC_DEFUN(AC_CHECK_INTP_GETSOCKOPT,
-[AC_MSG_CHECKING([ifelse([$1], , [if getsockopt() needs int* parameters],
-[if getsockopt() needs int* parameters (in $1)])])
-AH_TEMPLATE(HAVE_INTP_GETSOCKOPT, [Define if your system declares argument 5 of getsockopt()
-   as int * instead of size_t * or socklen_t.])
-ifelse([$1], , [ac_includes=""
-],
-[ac_includes=""
-for ac_header in $1
-do
-  ac_includes="$ac_includes
-#include<$ac_header>"
-done])
-AC_CACHE_VAL(ac_cv_prototype_intp_getsockopt,
-[AC_TRY_COMPILE(
-[#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-]
-,
-[
-  int i;
-  size_t optlen;
-  i = getsockopt(0, 0, 0, 0, &optlen);
-],
-eval "ac_cv_prototype_intp_getsockopt=no",
-[AC_TRY_COMPILE(
-[#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-]
-,
-[
-  int i;
-  int optlen;
-  i = getsockopt(0, 0, 0, 0, &optlen);
-],
-eval "ac_cv_prototype_intp_getsockopt=yes", eval "ac_cv_prototype_intp_getsockopt=no")])])
-if eval "test \"`echo $ac_cv_prototype_intp_getsockopt`\" = yes"; then
-  AC_MSG_RESULT(yes)
-  AC_DEFINE(HAVE_INTP_GETSOCKOPT)
-  ifelse([$2], , :, [$2])
-else
-  AC_MSG_RESULT(no)
-  ifelse([$3], , , [$3])
-fi
-])
-
-
-dnl AC_CXX_STD_NOTHROW checks if the compiler supports non-throwing new using
-dnl std::nothrow.
-dnl
-AC_DEFUN([AC_CXX_STD_NOTHROW],
-[AH_TEMPLATE(HAVE_STD__NOTHROW, [Define if the compiler supports std::nothrow.])
-AC_CACHE_CHECK(whether the compiler supports std::nothrow,
-ac_cv_cxx_std_nothrow,
-[AC_LANG_SAVE
- AC_LANG_CPLUSPLUS
- AC_TRY_COMPILE([#include <new>],[int *i = new (std::nothrow) int],
- ac_cv_cxx_std_nothrow=yes, ac_cv_cxx_std_nothrow=no)
- AC_LANG_RESTORE
-])
-if test "$ac_cv_cxx_std_nothrow" = yes; then
-  AC_DEFINE(HAVE_STD__NOTHROW)
-fi
-])
-
-
-dnl AC_CXX_NOTHROW_DELETE checks if the compiler supports non-throwing delete using
-dnl std::nothrow.
-dnl
-AC_DEFUN([AC_CXX_NOTHROW_DELETE],
-[AH_TEMPLATE(HAVE_NOTHROW_DELETE, [Define if the compiler supports operator delete (std::nothrow).])
-AC_CACHE_CHECK(whether the compiler supports operator delete (std::nothrow),
-ac_cv_cxx_nothrow_delete,
-[AC_LANG_SAVE
- AC_LANG_CPLUSPLUS
- AC_TRY_COMPILE([#include <new>],[int *i = new (std::nothrow) int; operator delete (i,std::nothrow)],
- ac_cv_cxx_nothrow_delete=yes, ac_cv_cxx_nothrow_delete=no)
- AC_LANG_RESTORE
-])
-if test "$ac_cv_cxx_nothrow_delete" = yes; then
-  AC_DEFINE(HAVE_NOTHROW_DELETE)
-fi
-])
-
-
 dnl AC_CXX_STATIC_ASSERT checks if the compiler supports static_assert.
 dnl
 AC_DEFUN([AC_CXX_STATIC_ASSERT],
index 5b46e1b2a2cdcea4e1860b1e0064fa3701a16128..87b1c260523f1ae30cb796c6ac3ccb010e281bf4 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for dcmtk 3.6.9.
+# Generated by GNU Autoconf 2.69 for dcmtk 3.7.0.
 #
 # Report bugs to <bugs@dcmtk.org>.
 #
@@ -579,9 +579,9 @@ MAKEFLAGS=
 
 # Identity of this package.
 PACKAGE_NAME='dcmtk'
-PACKAGE_TARNAME='dcmtk-3.6.9'
-PACKAGE_VERSION='3.6.9'
-PACKAGE_STRING='dcmtk 3.6.9'
+PACKAGE_TARNAME='dcmtk-3.7.0'
+PACKAGE_VERSION='3.7.0'
+PACKAGE_STRING='dcmtk 3.7.0'
 PACKAGE_BUGREPORT='bugs@dcmtk.org'
 PACKAGE_URL='https://www.dcmtk.org/'
 
@@ -804,13 +804,13 @@ bindir='${exec_prefix}/bin'
 sbindir='${exec_prefix}/sbin'
 libexecdir='${exec_prefix}/libexec'
 datarootdir='${prefix}/share'
-datadir='${datarootdir}/dcmtk-3.6.9'
-sysconfdir='${prefix}/etc/dcmtk-3.6.9'
+datadir='${datarootdir}/dcmtk-3.7.0'
+sysconfdir='${prefix}/etc/dcmtk-3.7.0'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/dcmtk-3.6.9'
+docdir='${datarootdir}/doc/dcmtk-3.7.0'
 infodir='${datarootdir}/info'
 htmldir='${docdir}/html'
 dvidir='${docdir}'
@@ -1310,7 +1310,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures dcmtk 3.6.9 to adapt to many kinds of systems.
+\`configure' configures dcmtk 3.7.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1347,18 +1347,18 @@ Fine tuning of the installation directories:
   --bindir=DIR            user executables [EPREFIX/bin]
   --sbindir=DIR           system admin executables [EPREFIX/sbin]
   --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc/dcmtk-3.6.9]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc/dcmtk-3.7.0]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
   --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only arch.-independent data [DATAROOTDIR/dcmtk-3.6.9]
+  --datadir=DIR           read-only arch.-independent data [DATAROOTDIR/dcmtk-3.7.0]
   --infodir=DIR           info documentation [DATAROOTDIR/info]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
   --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/dcmtk-3.6.9]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/dcmtk-3.7.0]
   --htmldir=DIR           html documentation [DOCDIR/html]
   --dvidir=DIR            dvi documentation [DOCDIR]
   --pdfdir=DIR            pdf documentation [DOCDIR]
@@ -1375,7 +1375,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of dcmtk 3.6.9:";;
+     short | recursive ) echo "Configuration of dcmtk 3.7.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1465,7 +1465,7 @@ Optional Packages:
   --without-openjpeg      don't include OpenJPEG support
   --with-libsndfileinc=DIR
                           location of libsndfile includes and libraries
-  --with-libsndfile       include libsndfile support (default: auto)
+  --with-libsndfile       include libsndfile support (default: no)
   --without-libsndfile    don't include libsndfile support
   --with-libiconvinc=DIR  location of libiconv includes and libraries
   --with-libiconv         include libiconv support (default: auto)
@@ -1551,7 +1551,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-dcmtk configure 3.6.9
+dcmtk configure 3.7.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2411,7 +2411,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by dcmtk $as_me 3.6.9, which was
+It was created by dcmtk $as_me 3.7.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2845,9 +2845,9 @@ ac_config_headers="$ac_config_headers include/dcmtk/config/osconfig.h"
 
 
 
-PACKAGE_VERSION_NUMBER=368
-PACKAGE_VERSION_SUFFIX="+"
-PACKAGE_DATE="DEV"
+PACKAGE_VERSION_NUMBER=370
+PACKAGE_VERSION_SUFFIX=""
+PACKAGE_DATE="2025-12-15"
 
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_VERSION_NUMBER ${PACKAGE_VERSION_NUMBER}
@@ -5554,18 +5554,6 @@ _ACEOF
 fi
 
 
-ac_fn_c_check_type "$LINENO" "sigjmp_buf" "ac_cv_type_sigjmp_buf" "#include <setjmp.h>
-"
-if test "x$ac_cv_type_sigjmp_buf" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_SIGJMP_BUF 1
-_ACEOF
-
-
-fi
-
-
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5
 $as_echo_n "checking for working memcmp... " >&6; }
@@ -5674,47 +5662,23 @@ _ACEOF
 fi
 done
 
-for ac_func in itoa atoll
-do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-done
-
-for ac_func in bcmp
-do :
-  ac_fn_c_check_func "$LINENO" "bcmp" "ac_cv_func_bcmp"
-if test "x$ac_cv_func_bcmp" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_BCMP 1
-_ACEOF
-
-fi
-done
-
-for ac_func in getpid mktemp mkstemp
+for ac_func in atoll
 do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  ac_fn_c_check_func "$LINENO" "atoll" "ac_cv_func_atoll"
+if test "x$ac_cv_func_atoll" = xyes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_ATOLL 1
 _ACEOF
 
 fi
 done
 
-for ac_func in stat
+for ac_func in mkstemp
 do :
-  ac_fn_c_check_func "$LINENO" "stat" "ac_cv_func_stat"
-if test "x$ac_cv_func_stat" = xyes; then :
+  ac_fn_c_check_func "$LINENO" "mkstemp" "ac_cv_func_mkstemp"
+if test "x$ac_cv_func_mkstemp" = xyes; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_STAT 1
+#define HAVE_MKSTEMP 1
 _ACEOF
 
 fi
@@ -5731,18 +5695,6 @@ _ACEOF
 fi
 done
 
-for ac_func in strdup index rindex access
-do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-done
-
 for ac_func in uname cuserid getlogin getlogin_r
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -5778,17 +5730,6 @@ _ACEOF
 fi
 done
 
-for ac_func in listen
-do :
-  ac_fn_c_check_func "$LINENO" "listen" "ac_cv_func_listen"
-if test "x$ac_cv_func_listen" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LISTEN 1
-_ACEOF
-
-fi
-done
-
 for ac_func in gethostbyname_r
 do :
   ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r"
@@ -5812,17 +5753,6 @@ _ACEOF
 fi
 done
 
-for ac_func in getrusage
-do :
-  ac_fn_c_check_func "$LINENO" "getrusage" "ac_cv_func_getrusage"
-if test "x$ac_cv_func_getrusage" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_GETRUSAGE 1
-_ACEOF
-
-fi
-done
-
 for ac_func in gettimeofday
 do :
   ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
@@ -5892,17 +5822,6 @@ _ACEOF
 fi
 done
 
-for ac_func in vsnprintf
-do :
-  ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
-if test "x$ac_cv_func_vsnprintf" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_VSNPRINTF 1
-_ACEOF
-
-fi
-done
-
 for ac_func in popen pclose
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -5996,8 +5915,6 @@ fi
 
 
 
-
-
 for ac_func in ftime gmtime_r localtime_r lstat nanosleep fcntl
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -6048,41 +5965,6 @@ done
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
-$as_echo_n "checking for socklen_t... " >&6; }
-if ${ac_cv_type_socklen_t+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <sys/types.h>
-   #include <sys/socket.h>
-int
-main ()
-{
-socklen_t len = 42; return 0;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_type_socklen_t=yes
-else
-  ac_cv_type_socklen_t=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5
-$as_echo "$ac_cv_type_socklen_t" >&6; }
-  if test $ac_cv_type_socklen_t != yes; then
-    $as_echo "#define socklen_t int" >>confdefs.h
-
-  fi
-
-
-
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <errno.h>
@@ -6223,22 +6105,6 @@ fi
 
 
 
-SAVELIBS="$LIBS"
-LIBS="$LIBS -lm"
-for ac_func in finite
-do :
-  ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite"
-if test "x$ac_cv_func_finite" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_FINITE 1
-_ACEOF
-
-fi
-done
-
-LIBS="$SAVELIBS"
-
-
 ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -6247,143 +6113,6 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 
 
 
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports std::nothrow" >&5
-$as_echo_n "checking whether the compiler supports std::nothrow... " >&6; }
-if ${ac_cv_cxx_std_nothrow+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <new>
-int
-main ()
-{
-int *i = new (std::nothrow) int
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_cv_cxx_std_nothrow=yes
-else
-  ac_cv_cxx_std_nothrow=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_std_nothrow" >&5
-$as_echo "$ac_cv_cxx_std_nothrow" >&6; }
-if test "$ac_cv_cxx_std_nothrow" = yes; then
-  $as_echo "#define HAVE_STD__NOTHROW 1" >>confdefs.h
-
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports operator delete (std::nothrow)" >&5
-$as_echo_n "checking whether the compiler supports operator delete (std::nothrow)... " >&6; }
-if ${ac_cv_cxx_nothrow_delete+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <new>
-int
-main ()
-{
-int *i = new (std::nothrow) int; operator delete (i,std::nothrow)
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_cv_cxx_nothrow_delete=yes
-else
-  ac_cv_cxx_nothrow_delete=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_nothrow_delete" >&5
-$as_echo "$ac_cv_cxx_nothrow_delete" >&6; }
-if test "$ac_cv_cxx_nothrow_delete" = yes; then
-  $as_echo "#define HAVE_NOTHROW_DELETE 1" >>confdefs.h
-
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports static_assert" >&5
-$as_echo_n "checking whether the compiler supports static_assert... " >&6; }
-if ${ac_cv_cxx_static_assert+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <cassert>
-int
-main ()
-{
-static_assert(true, "good")
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ac_cv_cxx_static_assert=yes
-else
-  ac_cv_cxx_static_assert=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_static_assert" >&5
-$as_echo "$ac_cv_cxx_static_assert" >&6; }
-if test "$ac_cv_cxx_static_assert" = yes; then
-  $as_echo "#define HAVE_STATIC_ASSERT 1" >>confdefs.h
-
-fi
-
-
-
 DEBUG="-DNDEBUG"
 DEBUGCXXFLAGS=
 DEBUGCFLAGS=
@@ -6492,6 +6221,7 @@ fi
 
 
 
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lg++" >&5
 $as_echo_n "checking for -lg++... " >&6; }
 if ${ac_cv_lib_gxx+:} false; then :
@@ -6536,13 +6266,15 @@ $as_echo "no" >&6; }
 fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5
-$as_echo_n "checking for main in -lnsl... " >&6; }
-if ${ac_cv_lib_nsl_main+:} false; then :
+OPENSSLLIBS=""
+OPENJPEGLIBS=""
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5
+$as_echo_n "checking for main in -ldl... " >&6; }
+if ${ac_cv_lib_dl_main+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnsl  $LIBS"
+LIBS="-ldl  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -6556,33 +6288,31 @@ return main ();
 }
 _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_nsl_main=yes
+  ac_cv_lib_dl_main=yes
 else
-  ac_cv_lib_nsl_main=no
+  ac_cv_lib_dl_main=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5
-$as_echo "$ac_cv_lib_nsl_main" >&6; }
-if test "x$ac_cv_lib_nsl_main" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBNSL 1
-_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5
+$as_echo "$ac_cv_lib_dl_main" >&6; }
+if test "x$ac_cv_lib_dl_main" = xyes; then :
 
-  LIBS="-lnsl $LIBS"
+OPENSSLLIBS="-ldl"
+OPENJPEGLIBS="-ldl"
 
 fi
 
-if test $ac_cv_lib_nsl_main = no ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
-$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
-if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+if test $ac_cv_lib_dl_main = no ; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnsl  $LIBS"
+LIBS="-ldl  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -6592,43 +6322,43 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char gethostbyname ();
+char dlopen ();
 int
 main ()
 {
-return gethostbyname ();
+return dlopen ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_nsl_gethostbyname=yes
+  ac_cv_lib_dl_dlopen=yes
 else
-  ac_cv_lib_nsl_gethostbyname=no
+  ac_cv_lib_dl_dlopen=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
-$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
-if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBNSL 1
-_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
 
-  LIBS="-lnsl $LIBS"
+OPENSSLLIBS="-ldl"
+OPENJPEGLIBS="-ldl"
 
 fi
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5
-$as_echo_n "checking for main in -lsocket... " >&6; }
-if ${ac_cv_lib_socket_main+:} false; then :
+
+MATHLIBS=""
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5
+$as_echo_n "checking for main in -lm... " >&6; }
+if ${ac_cv_lib_m_main+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsocket  $LIBS"
+LIBS="-lm  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -6642,33 +6372,30 @@ return main ();
 }
 _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_socket_main=yes
+  ac_cv_lib_m_main=yes
 else
-  ac_cv_lib_socket_main=no
+  ac_cv_lib_m_main=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5
-$as_echo "$ac_cv_lib_socket_main" >&6; }
-if test "x$ac_cv_lib_socket_main" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBSOCKET 1
-_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5
+$as_echo "$ac_cv_lib_m_main" >&6; }
+if test "x$ac_cv_lib_m_main" = xyes; then :
 
-  LIBS="-lsocket $LIBS"
+MATHLIBS="-lm"
 
 fi
 
-if test $ac_cv_lib_socket_main = no ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
-$as_echo_n "checking for socket in -lsocket... " >&6; }
-if ${ac_cv_lib_socket_socket+:} false; then :
+if test $ac_cv_lib_m_main = no ; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5
+$as_echo_n "checking for sin in -lm... " >&6; }
+if ${ac_cv_lib_m_sin+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsocket  $LIBS"
+LIBS="-lm  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -6678,189 +6405,19 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char socket ();
+char sin ();
 int
 main ()
 {
-return socket ();
+return sin ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_socket_socket=yes
+  ac_cv_lib_m_sin=yes
 else
-  ac_cv_lib_socket_socket=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5
-$as_echo "$ac_cv_lib_socket_socket" >&6; }
-if test "x$ac_cv_lib_socket_socket" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBSOCKET 1
-_ACEOF
-
-  LIBS="-lsocket $LIBS"
-
-fi
-
-fi
-
-OPENSSLLIBS=""
-OPENJPEGLIBS=""
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5
-$as_echo_n "checking for main in -ldl... " >&6; }
-if ${ac_cv_lib_dl_main+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_dl_main=yes
-else
-  ac_cv_lib_dl_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5
-$as_echo "$ac_cv_lib_dl_main" >&6; }
-if test "x$ac_cv_lib_dl_main" = xyes; then :
-
-OPENSSLLIBS="-ldl"
-OPENJPEGLIBS="-ldl"
-
-fi
-
-if test $ac_cv_lib_dl_main = no ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_dl_dlopen=yes
-else
-  ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-
-OPENSSLLIBS="-ldl"
-OPENJPEGLIBS="-ldl"
-
-fi
-
-fi
-
-MATHLIBS=""
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5
-$as_echo_n "checking for main in -lm... " >&6; }
-if ${ac_cv_lib_m_main+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_m_main=yes
-else
-  ac_cv_lib_m_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5
-$as_echo "$ac_cv_lib_m_main" >&6; }
-if test "x$ac_cv_lib_m_main" = xyes; then :
-
-MATHLIBS="-lm"
-
-fi
-
-if test $ac_cv_lib_m_main = no ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5
-$as_echo_n "checking for sin in -lm... " >&6; }
-if ${ac_cv_lib_m_sin+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sin ();
-int
-main ()
-{
-return sin ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_m_sin=yes
-else
-  ac_cv_lib_m_sin=no
+  ac_cv_lib_m_sin=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
@@ -7375,18 +6932,6 @@ fi
 
 done
 
-for ac_header in fcntl.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default"
-if test "x$ac_cv_header_fcntl_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_FCNTL_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in fnmatch.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default"
@@ -7459,18 +7004,6 @@ fi
 
 done
 
-for ac_header in malloc.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
-if test "x$ac_cv_header_malloc_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_MALLOC_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in mqueue.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "mqueue.h" "ac_cv_header_mqueue_h" "$ac_includes_default"
@@ -7555,18 +7088,6 @@ fi
 
 done
 
-for ac_header in stdint.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdint_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_STDINT_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in strings.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
@@ -7591,18 +7112,6 @@ fi
 
 done
 
-for ac_header in sys/errno.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "sys/errno.h" "ac_cv_header_sys_errno_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_errno_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_ERRNO_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in sys/file.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "sys/file.h" "ac_cv_header_sys_file_h" "$ac_includes_default"
@@ -7675,18 +7184,6 @@ fi
 
 done
 
-for ac_header in sys/stat.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_stat_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_STAT_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in sys/syscall.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "sys/syscall.h" "ac_cv_header_sys_syscall_h" "$ac_includes_default"
@@ -7735,18 +7232,6 @@ fi
 
 done
 
-for ac_header in sys/types.h
-do :
-  ac_fn_cxx_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_types_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_SYS_TYPES_H 1
-_ACEOF
-
-fi
-
-done
-
 for ac_header in sys/un.h
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default"
@@ -8787,39 +8272,6 @@ if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then
 
 fi
 
-# The cast to long int works around a bug in the HP C Compiler
-# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
-# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5
-$as_echo_n "checking size of short... " >&6; }
-if ${ac_cv_sizeof_short+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short"        "$ac_includes_default"; then :
-
-else
-  if test "$ac_cv_type_short" = yes; then
-     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (short)
-See \`config.log' for more details" "$LINENO" 5; }
-   else
-     ac_cv_sizeof_short=0
-   fi
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5
-$as_echo "$ac_cv_sizeof_short" >&6; }
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_SHORT $ac_cv_sizeof_short
-_ACEOF
-
-
 # The cast to long int works around a bug in the HP C Compiler
 # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
 # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
@@ -8890,104 +8342,38 @@ _ACEOF
 # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
 # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
 # This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5
-$as_echo_n "checking size of float... " >&6; }
-if ${ac_cv_sizeof_float+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if ${ac_cv_sizeof_void_p+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float"        "$ac_includes_default"; then :
+  if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
 
 else
-  if test "$ac_cv_type_float" = yes; then
+  if test "$ac_cv_type_void_p" = yes; then
      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (float)
+as_fn_error 77 "cannot compute sizeof (void *)
 See \`config.log' for more details" "$LINENO" 5; }
    else
-     ac_cv_sizeof_float=0
+     ac_cv_sizeof_void_p=0
    fi
 fi
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5
-$as_echo "$ac_cv_sizeof_float" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
 
 
 
 cat >>confdefs.h <<_ACEOF
-#define SIZEOF_FLOAT $ac_cv_sizeof_float
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
 _ACEOF
 
 
-# The cast to long int works around a bug in the HP C Compiler
-# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
-# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5
-$as_echo_n "checking size of double... " >&6; }
-if ${ac_cv_sizeof_double+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double"        "$ac_includes_default"; then :
-
-else
-  if test "$ac_cv_type_double" = yes; then
-     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (double)
-See \`config.log' for more details" "$LINENO" 5; }
-   else
-     ac_cv_sizeof_double=0
-   fi
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5
-$as_echo "$ac_cv_sizeof_double" >&6; }
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_DOUBLE $ac_cv_sizeof_double
-_ACEOF
-
-
-# The cast to long int works around a bug in the HP C Compiler
-# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
-# This bug is HP SR number 8606223364.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
-$as_echo_n "checking size of void *... " >&6; }
-if ${ac_cv_sizeof_void_p+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
-
-else
-  if test "$ac_cv_type_void_p" = yes; then
-     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (void *)
-See \`config.log' for more details" "$LINENO" 5; }
-   else
-     ac_cv_sizeof_void_p=0
-   fi
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
-$as_echo "$ac_cv_sizeof_void_p" >&6; }
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
-_ACEOF
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
-$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
-if ${ac_cv_struct_tm+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if ${ac_cv_struct_tm+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -9115,65 +8501,6 @@ $as_echo "$ac_cv_have___func___macro" >&6; }
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for feenableexcept (in fenv.h)" >&5
-$as_echo_n "checking prototype for feenableexcept (in fenv.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in fenv.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo feenableexcept | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct feenableexcept(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_FEENABLEEXCEPT 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for _stricmp (in string.h)" >&5
 $as_echo_n "checking prototype for _stricmp (in string.h)... " >&6; }
 
@@ -9233,162 +8560,12 @@ else
 $as_echo "no" >&6; }
 fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if accept() needs int* parameters (in sys/types.h sys/socket.h)" >&5
-$as_echo_n "checking if accept() needs int* parameters (in sys/types.h sys/socket.h)... " >&6; }
-
-ac_includes=""
-for ac_header in sys/types.h sys/socket.h
-do
-  ac_includes="$ac_includes
-#include<$ac_header>"
-done
-if ${ac_cv_prototype_intp_accept+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-
-
-int
-main ()
-{
-
-  int i;
-  struct sockaddr *addr;
-  size_t addrlen;
-
-  addr = 0;
-  addrlen = 0;
-  i = accept(1, addr, &addrlen);
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_intp_accept=no"
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-
-
-int
-main ()
-{
-
-  int i;
-  struct sockaddr *addr;
-  int addrlen;
-
-  addr = 0;
-  addrlen = 0;
-  i = accept(1, addr, &addrlen);
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_intp_accept=yes"
-else
-  eval "ac_cv_prototype_intp_accept=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-if eval "test \"`echo $ac_cv_prototype_intp_accept`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_INTP_ACCEPT 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for finite (in math.h)" >&5
-$as_echo_n "checking prototype for finite (in math.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in math.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo finite | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct finite(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_FINITE 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for std::isinf (in cmath)" >&5
-$as_echo_n "checking prototype for std::isinf (in cmath)... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for flock (in sys/file.h)" >&5
+$as_echo_n "checking prototype for flock (in sys/file.h)... " >&6; }
 
 :
 ac_includes=""
-for ac_header in cmath
+for ac_header in sys/file.h
 do
   ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
   if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
@@ -9396,7 +8573,7 @@ do
 #include<$ac_header>"
   fi
 done
-tmp_save_1=`echo std::isinf | tr ' :' '__'`
+tmp_save_1=`echo flock | tr ' :' '__'`
 if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9413,7 +8590,7 @@ typedef union { int member; } dummyStruct;
 #ifdef __cplusplus
 extern "C"
 #endif
-dummyStruct std::isinf(dummyStruct);
+dummyStruct flock(dummyStruct);
 
 
 int
@@ -9434,7 +8611,7 @@ fi
 if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_STD__ISINF 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_FLOCK 1" >>confdefs.h
 
   :
 else
@@ -9442,307 +8619,12 @@ else
 $as_echo "no" >&6; }
 fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for std::isnan (in cmath)" >&5
-$as_echo_n "checking prototype for std::isnan (in cmath)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in cmath
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo std::isnan | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct std::isnan(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_STD__ISNAN 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for flock (in sys/file.h)" >&5
-$as_echo_n "checking prototype for flock (in sys/file.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in sys/file.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo flock | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct flock(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_FLOCK 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostbyname_r (in libc.h unistd.h stdlib.h netdb.h)" >&5
-$as_echo_n "checking prototype for gethostbyname_r (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in libc.h unistd.h stdlib.h netdb.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo gethostbyname_r | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct gethostbyname_r(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_GETHOSTBYNAME_R 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostbyaddr_r (in libc.h unistd.h stdlib.h netdb.h)" >&5
-$as_echo_n "checking prototype for gethostbyaddr_r (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in libc.h unistd.h stdlib.h netdb.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo gethostbyaddr_r | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct gethostbyaddr_r(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_GETHOSTBYADDR_R 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostid (in libc.h unistd.h stdlib.h netdb.h)" >&5
-$as_echo_n "checking prototype for gethostid (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
-
-:
-ac_includes=""
-for ac_header in libc.h unistd.h stdlib.h netdb.h
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo gethostid | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
-#ifdef __cplusplus
-}
-#endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct gethostid(dummyStruct);
-
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
-else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_GETHOSTID 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for strerror_r (in string.h)" >&5
-$as_echo_n "checking prototype for strerror_r (in string.h)... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostbyname_r (in libc.h unistd.h stdlib.h netdb.h)" >&5
+$as_echo_n "checking prototype for gethostbyname_r (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
 
 :
 ac_includes=""
-for ac_header in string.h
+for ac_header in libc.h unistd.h stdlib.h netdb.h
 do
   ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
   if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
@@ -9750,7 +8632,7 @@ do
 #include<$ac_header>"
   fi
 done
-tmp_save_1=`echo strerror_r | tr ' :' '__'`
+tmp_save_1=`echo gethostbyname_r | tr ' :' '__'`
 if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9767,7 +8649,7 @@ typedef union { int member; } dummyStruct;
 #ifdef __cplusplus
 extern "C"
 #endif
-dummyStruct strerror_r(dummyStruct);
+dummyStruct gethostbyname_r(dummyStruct);
 
 
 int
@@ -9788,7 +8670,7 @@ fi
 if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_STRERROR_R 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_GETHOSTBYNAME_R 1" >>confdefs.h
 
   :
 else
@@ -9796,17 +8678,21 @@ else
 $as_echo "no" >&6; }
 fi
 
-if test $ac_cv_prototype_strerror_r = yes ; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if strerror_r() returns a char * (in string.h)" >&5
-$as_echo_n "checking if strerror_r() returns a char * (in string.h)... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostbyaddr_r (in libc.h unistd.h stdlib.h netdb.h)" >&5
+$as_echo_n "checking prototype for gethostbyaddr_r (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
 
+:
 ac_includes=""
-for ac_header in string.h
+for ac_header in libc.h unistd.h stdlib.h netdb.h
 do
-  ac_includes="$ac_includes
+  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
+  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
+    ac_includes="$ac_includes
 #include<$ac_header>"
+  fi
 done
-if ${ac_cv_prototype_charp_strerror_r+:} false; then :
+tmp_save_1=`echo gethostbyaddr_r | tr ' :' '__'`
+if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -9818,51 +8704,54 @@ $ac_includes
 #ifdef __cplusplus
 }
 #endif
+typedef union { int member; } dummyStruct;
+#ifdef __cplusplus
+extern "C"
+#endif
+dummyStruct gethostbyaddr_r(dummyStruct);
 
 
 int
 main ()
 {
 
-  char *buf = 0;
-  int i = strerror_r(0, buf, 100)
-
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_charp_strerror_r=no"
+  eval "ac_cv_prototype_$tmp_save_1=no"
 else
-  eval "ac_cv_prototype_charp_strerror_r=yes"
-
+  eval "ac_cv_prototype_$tmp_save_1=yes"
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
-if eval "test \"`echo $ac_cv_prototype_charp_strerror_r`\" = yes"; then
+if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_CHARP_STRERROR_R 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_GETHOSTBYADDR_R 1" >>confdefs.h
 
   :
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
 fi
 
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if getsockopt() needs int* parameters (in sys/types.h sys/socket.h)" >&5
-$as_echo_n "checking if getsockopt() needs int* parameters (in sys/types.h sys/socket.h)... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gethostid (in libc.h unistd.h stdlib.h netdb.h)" >&5
+$as_echo_n "checking prototype for gethostid (in libc.h unistd.h stdlib.h netdb.h)... " >&6; }
 
+:
 ac_includes=""
-for ac_header in sys/types.h sys/socket.h
+for ac_header in libc.h unistd.h stdlib.h netdb.h
 do
-  ac_includes="$ac_includes
+  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
+  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
+    ac_includes="$ac_includes
 #include<$ac_header>"
+  fi
 done
-if ${ac_cv_prototype_intp_getsockopt+:} false; then :
+tmp_save_1=`echo gethostid | tr ' :' '__'`
+if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -9874,74 +8763,45 @@ $ac_includes
 #ifdef __cplusplus
 }
 #endif
-
-
-int
-main ()
-{
-
-  int i;
-  size_t optlen;
-  i = getsockopt(0, 0, 0, 0, &optlen);
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_intp_getsockopt=no"
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-$ac_includes
+typedef union { int member; } dummyStruct;
 #ifdef __cplusplus
-}
+extern "C"
 #endif
+dummyStruct gethostid(dummyStruct);
 
 
 int
 main ()
 {
 
-  int i;
-  int optlen;
-  i = getsockopt(0, 0, 0, 0, &optlen);
-
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_intp_getsockopt=yes"
+  eval "ac_cv_prototype_$tmp_save_1=no"
 else
-  eval "ac_cv_prototype_intp_getsockopt=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  eval "ac_cv_prototype_$tmp_save_1=yes"
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
-if eval "test \"`echo $ac_cv_prototype_intp_getsockopt`\" = yes"; then
+if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_INTP_GETSOCKOPT 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_GETHOSTID 1" >>confdefs.h
 
   :
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-
 fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gettimeofday (in sys/time.h unistd.h)" >&5
-$as_echo_n "checking prototype for gettimeofday (in sys/time.h unistd.h)... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for strerror_r (in string.h)" >&5
+$as_echo_n "checking prototype for strerror_r (in string.h)... " >&6; }
 
 :
 ac_includes=""
-for ac_header in sys/time.h unistd.h
+for ac_header in string.h
 do
   ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
   if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
@@ -9949,7 +8809,7 @@ do
 #include<$ac_header>"
   fi
 done
-tmp_save_1=`echo gettimeofday | tr ' :' '__'`
+tmp_save_1=`echo strerror_r | tr ' :' '__'`
 if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9966,7 +8826,7 @@ typedef union { int member; } dummyStruct;
 #ifdef __cplusplus
 extern "C"
 #endif
-dummyStruct gettimeofday(dummyStruct);
+dummyStruct strerror_r(dummyStruct);
 
 
 int
@@ -9987,7 +8847,7 @@ fi
 if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_GETTIMEOFDAY 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_STRERROR_R 1" >>confdefs.h
 
   :
 else
@@ -9995,21 +8855,17 @@ else
 $as_echo "no" >&6; }
 fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for mktemp (in libc.h unistd.h stdlib.h)" >&5
-$as_echo_n "checking prototype for mktemp (in libc.h unistd.h stdlib.h)... " >&6; }
+if test $ac_cv_prototype_strerror_r = yes ; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if strerror_r() returns a char * (in string.h)" >&5
+$as_echo_n "checking if strerror_r() returns a char * (in string.h)... " >&6; }
 
-:
 ac_includes=""
-for ac_header in libc.h unistd.h stdlib.h
+for ac_header in string.h
 do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
+  ac_includes="$ac_includes
 #include<$ac_header>"
-  fi
 done
-tmp_save_1=`echo mktemp | tr ' :' '__'`
-if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
+if ${ac_cv_prototype_charp_strerror_r+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -10021,45 +8877,47 @@ $ac_includes
 #ifdef __cplusplus
 }
 #endif
-typedef union { int member; } dummyStruct;
-#ifdef __cplusplus
-extern "C"
-#endif
-dummyStruct mktemp(dummyStruct);
 
 
 int
 main ()
 {
 
+  char *buf = 0;
+  int i = strerror_r(0, buf, 100)
+
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_prototype_$tmp_save_1=no"
+  eval "ac_cv_prototype_charp_strerror_r=no"
 else
-  eval "ac_cv_prototype_$tmp_save_1=yes"
+  eval "ac_cv_prototype_charp_strerror_r=yes"
+
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
+
+if eval "test \"`echo $ac_cv_prototype_charp_strerror_r`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_MKTEMP 1" >>confdefs.h
+  $as_echo "#define HAVE_CHARP_STRERROR_R 1" >>confdefs.h
 
   :
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
+
 fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for mkstemp (in libc.h unistd.h stdlib.h)" >&5
-$as_echo_n "checking prototype for mkstemp (in libc.h unistd.h stdlib.h)... " >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking prototype for gettimeofday (in sys/time.h unistd.h)" >&5
+$as_echo_n "checking prototype for gettimeofday (in sys/time.h unistd.h)... " >&6; }
 
 :
 ac_includes=""
-for ac_header in libc.h unistd.h stdlib.h
+for ac_header in sys/time.h unistd.h
 do
   ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
   if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
@@ -10067,7 +8925,7 @@ do
 #include<$ac_header>"
   fi
 done
-tmp_save_1=`echo mkstemp | tr ' :' '__'`
+tmp_save_1=`echo gettimeofday | tr ' :' '__'`
 if eval \${ac_cv_prototype_$tmp_save_1+:} false; then :
   $as_echo_n "(cached) " >&6
 else
@@ -10084,7 +8942,7 @@ typedef union { int member; } dummyStruct;
 #ifdef __cplusplus
 extern "C"
 #endif
-dummyStruct mkstemp(dummyStruct);
+dummyStruct gettimeofday(dummyStruct);
 
 
 int
@@ -10105,7 +8963,7 @@ fi
 if eval "test \"`echo '$''{'ac_cv_prototype_$tmp_save_1'}'`\" = yes"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_MKSTEMP 1" >>confdefs.h
+  $as_echo "#define HAVE_PROTOTYPE_GETTIMEOFDAY 1" >>confdefs.h
 
   :
 else
 
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ standard namespace" >&5
-$as_echo_n "checking for C++ standard namespace... " >&6; }
-
-if ${ac_cv_check_std_namespace+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_link_o='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.o $LIBS 1>&5'
-cat > conftest.$ac_ext <<EOF
-#line 10421 "configure"
-#include "confdefs.h"
-
-#include <iostream>
-using namespace std;
-
-int main() {
-
-  cout << "Hello World" << endl;
-
-; return 0; }
-EOF
-if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link_o\""; } >&5
-  (eval $ac_link_o) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    rm -rf conftest*
-    eval "ac_cv_check_std_namespace=yes"
-  else
-    echo "configure: failed link was:" >&5
-    cat conftest.$ac_ext >&5
-      rm -rf conftest*
-      eval "ac_cv_check_std_namespace=no"
-      fi
-else
-  echo "configure: failed compile was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_check_std_namespace=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_check_std_namespace'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_STD_NAMESPACE 1" >>confdefs.h
-
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::vfprintf (in cstdarg cstdio)" >&5
-$as_echo_n "checking for std::vfprintf (in cstdarg cstdio)... " >&6; }
-
-ac_includes=""
-for ac_header in cstdarg cstdio
-do
-  ac_safe=`echo "$ac_header" | sed 'y%./+-%__p_%'`
-  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'}'`\" = yes"; then
-    ac_includes="$ac_includes
-#include<$ac_header>"
-  fi
-done
-tmp_save_1=`echo std::vfprintf | tr ' :' '__'`
-if eval \${ac_cv_compiles_$tmp_save_1+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$ac_includes
-int
-main ()
-{
-FILE *stream; va_list ap; std::vfprintf(stream, "", ap);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  eval "ac_cv_compiles_$tmp_save_1=yes"
-else
-  eval "ac_cv_compiles_$tmp_save_1=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-if eval "test \"`echo '$''{'ac_cv_compiles_$tmp_save_1'}'`\" = yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  $as_echo "#define HAVE_PROTOTYPE_STD__VFPRINTF 1" >>confdefs.h
-
-  :
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::vsnprintf (in cstdarg cstdio)" >&5
 $as_echo_n "checking for std::vsnprintf (in cstdarg cstdio)... " >&6; }
@@ -11965,10 +10723,8 @@ else
     #endif
     /* on some platforms, tcpd.h needs stdio.h */
     #include <stdio.h>
-    #ifdef HAVE_SYS_TYPES_H
     /* on some platforms, tcpd.h needs sys/types.h */
     #include <sys/types.h>
-    #endif
     #include <tcpd.h>
     #ifdef __cplusplus
     }
@@ -12123,21 +10879,9 @@ $as_echo_n "checking whether to include libsndfile support... " >&6; }
 if test "${with_libsndfile+set}" = set; then :
   withval=$with_libsndfile;  case "$withval" in
     yes)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-      $as_echo "#define WITH_SNDFILE 1" >>confdefs.h
-
-      SNDFILELIBS="-lsndfile"
-      ;;
-    *)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-      ;;
-    esac
-else
-   SAVELIBS="$LIBS"
-    LIBS="$LIBS -lsndfile"
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+      SAVELIBS="$LIBS"
+      LIBS="$LIBS -lsndfile"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <sndfile.h>
 int
@@ -12151,16 +10895,25 @@ _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-        $as_echo "#define WITH_SNDFILE 1" >>confdefs.h
+          $as_echo "#define WITH_SNDFILE 1" >>confdefs.h
 
-        SNDFILELIBS="-lsndfile"
+          SNDFILELIBS="-lsndfile"
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-    LIBS="$SAVELIBS"
+      LIBS="$SAVELIBS"
+      ;;
+    *)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+      ;;
+    esac
+else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
 fi
 
@@ -12168,6 +10921,7 @@ fi
 
 
 
+
 # Check whether --with-libiconvinc was given.
 if test "${with_libiconvinc+set}" = set; then :
   withval=$with_libiconvinc; case $withval in #(
@@ -13808,39 +12562,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
 
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iterator category contiguous is declared" >&5
-$as_echo_n "checking whether iterator category contiguous is declared... " >&6; }
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-            #include <iterator>
-            int main(){typedef std::contiguous_iterator_tag category;return 0;}
-
-
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  dcmtk_have_iter_cat=yes
-else
-  dcmtk_have_iter_cat=no
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-    if test "$dcmtk_have_iter_cat" = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CONTIGUOUS_ITERATOR_CATEGORY 1" >>confdefs.h
-
-    else
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-    fi
-
-
-
-
 CFLAGS="$DEBUGCFLAGS $CFLAGS"
 CXXFLAGS="$DEBUGCXXFLAGS $CXXFLAGS"
 
@@ -14367,7 +13088,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by dcmtk $as_me 3.6.9, which was
+This file was extended by dcmtk $as_me 3.7.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14430,7 +13151,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-dcmtk config.status 3.6.9
+dcmtk config.status 3.7.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 4b11cc5b6c135ade74437e30a5f8c08839ec08fe..87c7ce0a72d5da378ecf8493b3419194486eb61b 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(dcmtk, 3.6.9, [bugs@dcmtk.org], [dcmtk-3.6.9], [https://www.dcmtk.org/])
+AC_INIT(dcmtk, 3.7.0, [bugs@dcmtk.org], [dcmtk-3.7.0], [https://www.dcmtk.org/])
 AC_PREREQ(2.60)
 AC_CONFIG_SRCDIR(Makefile.in)
 AC_CONFIG_HEADERS(include/dcmtk/config/osconfig.h)
@@ -10,9 +10,9 @@ dnl -------------------------------------------------------
 dnl Additional Package Information
 dnl -------------------------------------------------------
 
-PACKAGE_VERSION_NUMBER=368
-PACKAGE_VERSION_SUFFIX="+"
-PACKAGE_DATE="DEV"
+PACKAGE_VERSION_NUMBER=370
+PACKAGE_VERSION_SUFFIX=""
+PACKAGE_DATE="2025-12-15"
 AC_DEFINE_UNQUOTED(PACKAGE_VERSION_NUMBER,${PACKAGE_VERSION_NUMBER},[Define to the version number of this package.])
 AC_DEFINE_UNQUOTED(PACKAGE_VERSION_SUFFIX,"${PACKAGE_VERSION_SUFFIX}",[Define to the version suffix of this package.])
 AC_DEFINE_UNQUOTED(PACKAGE_DATE,"${PACKAGE_DATE}",[Define to the release date of this package.])
@@ -224,8 +224,6 @@ AC_CHECK_TYPES(uint64_t)
 
 AC_CHECK_TYPES(char16_t)
 
-AC_CHECK_TYPES([sigjmp_buf], [], [], [[#include <setjmp.h>]])
-
 dnl -------------------------------------------------------
 dnl Check for libc library functions
 dnl -------------------------------------------------------
@@ -233,26 +231,20 @@ dnl -------------------------------------------------------
 AC_FUNC_MEMCMP
 AC_TYPE_SIGNAL
 AC_CHECK_FUNCS(gethostid sysinfo)
-AC_CHECK_FUNCS(itoa atoll)
-AC_CHECK_FUNCS(bcmp)
-AC_CHECK_FUNCS(getpid mktemp mkstemp)
-AC_CHECK_FUNCS(stat)
+AC_CHECK_FUNCS(atoll)
+AC_CHECK_FUNCS(mkstemp)
 AC_CHECK_FUNCS(malloc_debug)
-AC_CHECK_FUNCS(strdup index rindex access)
 AC_CHECK_FUNCS(uname cuserid getlogin getlogin_r)
 AC_CHECK_FUNCS(usleep)
 AC_CHECK_FUNCS(flock lockf)
-AC_CHECK_FUNCS(listen)
 AC_CHECK_FUNCS(gethostbyname_r)
 AC_CHECK_FUNCS(gethostbyaddr_r getgrnam_r getpwnam_r)
-AC_CHECK_FUNCS(getrusage)
 AC_CHECK_FUNCS(gettimeofday)
 AC_CHECK_FUNCS(waitpid)
 AC_CHECK_FUNCS(getuid geteuid setuid getpwnam getgrnam)
 AC_CHECK_FUNCS(sleep fork)
 AC_CHECK_FUNCS(_findfirst)
 AC_CHECK_FUNCS(strlcpy strlcat)
-AC_CHECK_FUNCS(vsnprintf)
 AC_CHECK_FUNCS(popen pclose)
 AC_CHECK_FUNCS(readdir_r)
 AC_FUNC_FSEEKO
@@ -261,24 +253,10 @@ dnl -------------------------------------------------------
 dnl Check for header files and functions needed by oflog
 dnl -------------------------------------------------------
 
-AC_DEFUN([TYPE_SOCKLEN_T],
-[
-AH_TEMPLATE(socklen_t, [Define to int if undefined.])
-AC_CACHE_CHECK([for socklen_t], ac_cv_type_socklen_t,
-[
-  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
-   #include <sys/socket.h>]], [[socklen_t len = 42; return 0;]])],[ac_cv_type_socklen_t=yes],[ac_cv_type_socklen_t=no])
-])
-  if test $ac_cv_type_socklen_t != yes; then
-    AC_DEFINE(socklen_t, int)
-  fi
-])
-
 AC_CHECK_FUNCS(ftime gmtime_r localtime_r lstat nanosleep fcntl)
 AC_CHECK_FUNCS(htons htonl ntohs ntohl)
 AC_CHECK_HEADERS(netinet/in.h)
 AC_CHECK_HEADERS(syslog.h)
-TYPE_SOCKLEN_T
 
 AH_TEMPLATE(HAVE_ENAMETOOLONG, [Define if your system provides ENAMETOOLONG errno value.])
 AC_COMPILE_IFELSE(
@@ -298,25 +276,12 @@ AC_CHECK_FUNCS(fgetln)
 
 AC_CHECK_PROTOTYPE(strcasestr, string.h)
 
-dnl -------------------------------------------------------
-dnl Check for libm library functions
-dnl -------------------------------------------------------
-
-SAVELIBS="$LIBS"
-LIBS="$LIBS -lm"
-AC_CHECK_FUNCS(finite)
-LIBS="$SAVELIBS"
-
 dnl -------------------------------------------------------
 dnl Perform remaining tests with C++ compiler
 dnl -------------------------------------------------------
 
 AC_LANG(C++)
 
-AC_CXX_STD_NOTHROW
-AC_CXX_NOTHROW_DELETE
-AC_CXX_STATIC_ASSERT
-
 dnl -------------------------------------------------------
 dnl Check for Debug Mode
 dnl -------------------------------------------------------
@@ -416,18 +381,6 @@ dnl -------------------------------------------------------
 
 AC_CHECK_GXXLIB
 
-dnl Some C++ compilers have problems with recursive main calls
-dnl (e.g. Sun C++ 4.2). In this case we must test another function
-dnl to link.
-AC_CHECK_LIB(nsl, main)
-if test $ac_cv_lib_nsl_main = no ; then
-AC_CHECK_LIB(nsl, gethostbyname)
-fi
-AC_CHECK_LIB(socket, main)
-if test $ac_cv_lib_socket_main = no ; then
-AC_CHECK_LIB(socket, socket)
-fi
-
 dnl Some newer versions of OpenSSL must be linked against libdl.
 dnl We just check whether libdl exists and in this case always
 dnl add -ldl to OPENSSLLIBS. The same applies for OPENJPEG.
@@ -476,14 +429,12 @@ AC_CHECK_TCP_H
 AC_CHECK_HEADERS(alloca.h)
 AC_CHECK_HEADERS(atomic)
 AC_CHECK_HEADERS(arpa/inet.h)
-AC_CHECK_HEADERS(fcntl.h)
 AC_CHECK_HEADERS(fnmatch.h)
 AC_CHECK_HEADERS(grp.h)
 AC_CHECK_HEADERS(ieeefp.h)
 AC_CHECK_HEADERS(io.h)
 AC_CHECK_HEADERS(iostream)
 AC_CHECK_HEADERS(libc.h)
-AC_CHECK_HEADERS(malloc.h)
 AC_CHECK_HEADERS(mqueue.h)
 AC_CHECK_HEADERS(new)
 AC_CHECK_HEADERS(netdb.h)
@@ -491,22 +442,18 @@ AC_CHECK_HEADERS(pthread.h)
 AC_CHECK_HEADERS(pwd.h)
 AC_CHECK_HEADERS(semaphore.h)
 AC_CHECK_HEADERS(cstddef)
-AC_CHECK_HEADERS(stdint.h)
 AC_CHECK_HEADERS(strings.h)
 AC_CHECK_HEADERS(synch.h)
-AC_CHECK_HEADERS(sys/errno.h)
 AC_CHECK_HEADERS(sys/file.h)
 AC_CHECK_HEADERS(sys/msg.h)
 AC_CHECK_HEADERS(sys/param.h)
 AC_CHECK_HEADERS(sys/resource.h)
 AC_CHECK_HEADERS(sys/select.h)
 AC_CHECK_HEADERS(sys/socket.h)
-AC_CHECK_HEADERS(sys/stat.h)
 AC_CHECK_HEADERS(sys/syscall.h)
 AC_CHECK_HEADERS(sys/systeminfo.h)
 AC_CHECK_HEADERS(sys/time.h)
 AC_CHECK_HEADERS(sys/timeb.h)
-AC_CHECK_HEADERS(sys/types.h)
 AC_CHECK_HEADERS(sys/un.h)
 AC_CHECK_HEADERS(sys/utime.h)
 AC_CHECK_HEADERS(sys/utsname.h)
@@ -737,11 +684,8 @@ dnl ------------------------------------------------------------
 AC_TYPEDEF(ssize_t, long)
 AC_TYPEDEF(pid_t, int)
 AC_C_CHAR_UNSIGNED
-AC_CHECK_SIZEOF(short)
 AC_CHECK_SIZEOF(int)
 AC_CHECK_SIZEOF(long)
-AC_CHECK_SIZEOF(float)
-AC_CHECK_SIZEOF(double)
 AC_CHECK_SIZEOF(void *)
 AC_STRUCT_TM
 AC_MY_SYMBOL_EXISTS([__FUNCTION__])
@@ -756,12 +700,7 @@ dnl The following AC_CHECK_* macros _must_ have corresponding entries in
 dnl the acconfig.h file.  This is because the macros are specific to the
 dnl DCMTK project and are not supported by GNU autoheader.
 
-AC_CHECK_PROTOTYPE(feenableexcept, fenv.h)
 AC_CHECK_PROTOTYPE(_stricmp, string.h)
-AC_CHECK_INTP_ACCEPT(sys/types.h sys/socket.h)
-AC_CHECK_PROTOTYPE(finite, math.h)
-AC_CHECK_PROTOTYPE(std::isinf, cmath)
-AC_CHECK_PROTOTYPE(std::isnan, cmath)
 AC_CHECK_PROTOTYPE(flock, sys/file.h)
 AC_CHECK_PROTOTYPE(gethostbyname_r, libc.h unistd.h stdlib.h netdb.h)
 AC_CHECK_PROTOTYPE(gethostbyaddr_r, libc.h unistd.h stdlib.h netdb.h)
@@ -770,23 +709,18 @@ AC_CHECK_PROTOTYPE(strerror_r, string.h)
 if test $ac_cv_prototype_strerror_r = yes ; then
 AC_CHECK_CHARP_STRERROR_R(string.h)
 fi
-AC_CHECK_INTP_GETSOCKOPT(sys/types.h sys/socket.h)
 AC_CHECK_PROTOTYPE(gettimeofday, sys/time.h unistd.h)
-AC_CHECK_PROTOTYPE(mktemp, libc.h unistd.h stdlib.h)
-AC_CHECK_PROTOTYPE(mkstemp, libc.h unistd.h stdlib.h)
 AC_CHECK_PROTOTYPE(strcasecmp, string.h)
 AC_CHECK_PROTOTYPE(strncasecmp, string.h)
 AC_CHECK_PROTOTYPE(usleep, libc.h unistd.h stdlib.h)
 AC_CHECK_PROTOTYPE(vsnprintf, stdio.h stdarg.h)
 AC_CHECK_PROTOTYPE(waitpid, sys/wait.h sys/time.h sys/resource.h)
 
+
 dnl -------------------------------------------------------
 dnl Check for the usage of standard C++ headers
 dnl -------------------------------------------------------
 
-AC_CHECK_STD_NAMESPACE
-AC_CHECK_COMPILES(std::vfprintf, cstdarg cstdio,
-  [FILE *stream; va_list ap; std::vfprintf(stream, "", ap);])
 AC_CHECK_COMPILES(std::vsnprintf, cstdarg cstdio,
   [char buf[256]; va_list ap; std::vsnprintf(buf, 0, "", ap);])
 
@@ -1156,10 +1090,8 @@ AS_HELP_STRING([--without-libwrap], [don't include libwrap support])],
     #endif
     /* on some platforms, tcpd.h needs stdio.h */
     #include <stdio.h>
-    #ifdef HAVE_SYS_TYPES_H
     /* on some platforms, tcpd.h needs sys/types.h */
     #include <sys/types.h>
-    #endif
     #include <tcpd.h>
     #ifdef __cplusplus
     }
@@ -1214,28 +1146,27 @@ SNDFILELIBS=""
 AC_MSG_CHECKING(whether to include libsndfile support)
 AH_TEMPLATE(WITH_SNDFILE, [Define if we are compiling with libsndfile support.])
 AC_ARG_WITH(libsndfile,
-  [AS_HELP_STRING([--with-libsndfile], [include libsndfile support (default: auto)])
+  [AS_HELP_STRING([--with-libsndfile], [include libsndfile support (default: no)])
 AS_HELP_STRING([--without-libsndfile], [don't include libsndfile support])],
   [ case "$withval" in
     yes)
-      AC_MSG_RESULT(yes)
-      AC_DEFINE(WITH_SNDFILE)
-      SNDFILELIBS="-lsndfile"
+      SAVELIBS="$LIBS"
+      LIBS="$LIBS -lsndfile"
+      AC_TRY_LINK([#include <sndfile.h>], [char buffer [128]; sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer));],
+        [ AC_MSG_RESULT(yes)
+          AC_DEFINE(WITH_SNDFILE)
+          SNDFILELIBS="-lsndfile" ],
+        [ AC_MSG_RESULT(no) ])
+      LIBS="$SAVELIBS"
       ;;
     *)
       AC_MSG_RESULT(no)
       ;;
     esac ],
-  [ SAVELIBS="$LIBS"
-    LIBS="$LIBS -lsndfile"
-    AC_TRY_LINK([#include <sndfile.h>], [char buffer [128]; sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer));],
-      [ AC_MSG_RESULT(yes)
-        AC_DEFINE(WITH_SNDFILE)
-        SNDFILELIBS="-lsndfile" ],
-      [AC_MSG_RESULT(no)])
-    LIBS="$SAVELIBS"]
+  [ AC_MSG_RESULT(no) ]
 )
 
+
 dnl -------------------------------------------------------
 dnl Check for libiconv support
 dnl -------------------------------------------------------
@@ -1793,13 +1724,6 @@ AC_TRY_COMPILE([#include <sys/syscall.h>],
   [AC_MSG_RESULT(no)])
 
 
-dnl -------------------------------------------------------
-dnl Test for defined iterator categories
-dnl -------------------------------------------------------
-
-AC_CHECK_ITERATOR_CATEGORY([contiguous],[HAVE_CONTIGUOUS_ITERATOR_CATEGORY])
-
-
 dnl -------------------------------------------------------
 dnl Set optimizer and debug compiler flags
 dnl -------------------------------------------------------
index 531d4be75110477bcab42e5fd66a8e401cfd6e33..ce45475d8ff53fbf0812f9e0f16b581df3388b39 100755 (executable)
@@ -668,13 +668,13 @@ bindir='${exec_prefix}/bin'
 sbindir='${exec_prefix}/sbin'
 libexecdir='${exec_prefix}/libexec'
 datarootdir='${prefix}/share'
-datadir='${datarootdir}/dcmtk-3.6.9'
-sysconfdir='${prefix}/etc/dcmtk-3.6.9'
+datadir='${datarootdir}/dcmtk-3.7.0'
+sysconfdir='${prefix}/etc/dcmtk-3.7.0'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/dcmtk-3.6.9'
+docdir='${datarootdir}/doc/dcmtk-3.7.0'
 infodir='${datarootdir}/info'
 htmldir='${docdir}/html'
 dvidir='${docdir}'
@@ -1211,18 +1211,18 @@ Fine tuning of the installation directories:
   --bindir=DIR            user executables [EPREFIX/bin]
   --sbindir=DIR           system admin executables [EPREFIX/sbin]
   --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc/dcmtk-3.6.9]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc/dcmtk-3.7.0]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
   --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only arch.-independent data [DATAROOTDIR/dcmtk-3.6.9]
+  --datadir=DIR           read-only arch.-independent data [DATAROOTDIR/dcmtk-3.7.0]
   --infodir=DIR           info documentation [DATAROOTDIR/info]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
   --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/dcmtk-3.6.9]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/dcmtk-3.7.0]
   --htmldir=DIR           html documentation [DOCDIR/html]
   --dvidir=DIR            dvi documentation [DOCDIR]
   --pdfdir=DIR            pdf documentation [DOCDIR]
index 57fe7e43e17f7b70758dcdebef3a4111dfdd6c90..cd9ff2f037e4621b5851201b20f03b1c01ed8505 100644 (file)
@@ -87,23 +87,6 @@ DCMTK_ENABLE_STRICT_HUFFMAN_TABLE_CHECK
     test (see DCMTK issue #1018).  The test has, therefore, been disabled.  This
     macro re-enables the old behavior.
 
-DCMTK_ENABLE_UNSAFE_VSNPRINTF
-  Affected: ofstd
-  Type of modification: Activates feature
-  Explanation: DCMTK requires the snprintf(3)/vsnprintf(3) function, which was
-    introduced with C99 and may not be supported by very old compilers.  As a
-    "last resort", an implementation internally using sprintf/vsprintf can be
-    enabled with this macro, which allows the user to compile DCMTK on platforms
-    that do not have the new functions.
-    The implementation allocates a buffer that is 1 kByte larger than the "size"
-    parameter, formats the string into that buffer, and then uses strlcpy() to
-    copy the formatted string into the output buffer, truncating if necessary.
-    This will work in most cases, since few snprintf calls should overrun their
-    buffer by more than 1K, but it can be easily abused by a malicious attacker
-    to cause a buffer overrun.
-    Therefore, this implementation should only be used as a "last resort" and we
-    strongly advise against using it in production code.
-
 DCMTK_GUI
   Affected: all modules
   Type of modification: Activates experimental or rarely used feature
index 76f8c71e6c777d651e92599e4bc703699010cdbc..70cf1b52cf0f7a65077aa3c1d961ff34b60b9341 100644 (file)
@@ -88,9 +88,6 @@
 #define ENVIRONMENT_PATH_SEPARATOR ':'
 #endif
 
-/* Define to 1 if you have the `access' function. */
-#undef HAVE_ACCESS
-
 /* Define to 1 if you have the <alloca.h> header file. */
 #undef HAVE_ALLOCA_H
 
 /* Define if the compiler supports __attribute__((deprecated("message"))). */
 #undef HAVE_ATTRIBUTE_DEPRECATED_MSG
 
-/* Define to 1 if you have the `bcmp' function. */
-#undef HAVE_BCMP
-
 /* Define to 1 if the system has the type `char16_t'. */
 #undef HAVE_CHAR16_T
 
    instead of int. */
 #undef HAVE_CHARP_STRERROR_R
 
-/* Define if the contiguous iterator category is supported. */
-#undef HAVE_CONTIGUOUS_ITERATOR_CATEGORY
-
 /* Define to 1 if you have the <cstddef> header file. */
 #undef HAVE_CSTDDEF
 
 /* Define to 1 if you have the `fcntl' function. */
 #undef HAVE_FCNTL
 
-/* Define to 1 if you have the <fcntl.h> header file. */
-#undef HAVE_FCNTL_H
-
 /* Define to 1 if you have the `fgetln' function. */
 #undef HAVE_FGETLN
 
-/* Define to 1 if you have the `finite' function. */
-#undef HAVE_FINITE
-
 /* Define to 1 if you have the `flock' function. */
 #undef HAVE_FLOCK
 
 /* Define to 1 if you have the `getlogin_r' function. */
 #undef HAVE_GETLOGIN_R
 
-/* Define to 1 if you have the `getpid' function. */
-#undef HAVE_GETPID
-
 /* Define to 1 if you have the `getpwnam' function. */
 #undef HAVE_GETPWNAM
 
 /* Define to 1 if you have the `getpwnam_r' function. */
 #undef HAVE_GETPWNAM_R
 
-/* Define to 1 if you have the `getrusage' function. */
-#undef HAVE_GETRUSAGE
-
 /* Define to 1 if you have the `gettimeofday' function. */
 #undef HAVE_GETTIMEOFDAY
 
 /* Define to 1 if you have the <ieeefp.h> header file. */
 #undef HAVE_IEEEFP_H
 
-/* Define to 1 if you have the `index' function. */
-#undef HAVE_INDEX
-
 /* Define to 1 if the system has the type `int64_t'. */
 #undef HAVE_INT64_T
 
-/* Define if your system declares argument 3 of accept() as int * instead of
-   size_t * or socklen_t *. */
-#undef HAVE_INTP_ACCEPT
-
-/* Define if your system declares argument 5 of getsockopt() as int * instead
-   of size_t * or socklen_t. */
-#undef HAVE_INTP_GETSOCKOPT
-
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
 /* Define to 1 if you have the <io.h> header file. */
 #undef HAVE_IO_H
 
-/* Define to 1 if you have the `itoa' function. */
-#undef HAVE_ITOA
-
 /* Define to 1 if you have the <langinfo.h> header file. */
 #undef HAVE_LANGINFO_H
 
 /* Define to 1 if you have the <libc.h> header file. */
 #undef HAVE_LIBC_H
 
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-#undef HAVE_LIBNSL
-
 /* Define to 1 if you have the <libpng/png.h> header file. */
 #undef HAVE_LIBPNG_PNG_H
 
-/* Define to 1 if you have the `socket' library (-lsocket). */
-#undef HAVE_LIBSOCKET
-
-/* Define to 1 if you have the `listen' function. */
-#undef HAVE_LISTEN
-
 /* Define to 1 if you have the `localtime_r' function. */
 #undef HAVE_LOCALTIME_R
 
 /* Define to 1 if you have the `malloc_debug' function. */
 #undef HAVE_MALLOC_DEBUG
 
-/* Define to 1 if you have the <malloc.h> header file. */
-#undef HAVE_MALLOC_H
-
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
 /* Define to 1 if you have the `mkstemp' function. */
 #undef HAVE_MKSTEMP
 
-/* Define to 1 if you have the `mktemp' function. */
-#undef HAVE_MKTEMP
-
 /* Define to 1 if you have the <mqueue.h> header file. */
 #undef HAVE_MQUEUE_H
 
 /* Define to 1 if you have the <new> header file. */
 #undef HAVE_NEW
 
-/* Define if the compiler supports operator delete (std::nothrow). */
-#undef HAVE_NOTHROW_DELETE
-
 /* Define `pid_t' to `int' if <sys/types.h> does not define. */
 #undef HAVE_NO_TYPEDEF_PID_T
 
@@ -482,12 +429,6 @@ typedef unsigned short ushort;
 /* Define to 1 if you have the `popen' function. */
 #undef HAVE_POPEN
 
-/* Define if your system has a prototype for feenableexcept in fenv.h. */
-#undef HAVE_PROTOTYPE_FEENABLEEXCEPT
-
-/* Define if your system has a prototype for finite in math.h. */
-#undef HAVE_PROTOTYPE_FINITE
-
 /* Define if your system has a prototype for flock in sys/file.h. */
 #undef HAVE_PROTOTYPE_FLOCK
 
@@ -507,24 +448,6 @@ typedef unsigned short ushort;
    unistd.h. */
 #undef HAVE_PROTOTYPE_GETTIMEOFDAY
 
-/* Define if your system has a prototype for mkstemp in libc.h unistd.h
-   stdlib.h. */
-#undef HAVE_PROTOTYPE_MKSTEMP
-
-/* Define if your system has a prototype for mktemp in libc.h unistd.h
-   stdlib.h. */
-#undef HAVE_PROTOTYPE_MKTEMP
-
-/* Define if your system has a prototype for std::isinf in cmath. */
-#undef HAVE_PROTOTYPE_STD__ISINF
-
-/* Define if your system has a prototype for std::isnan in cmath. */
-#undef HAVE_PROTOTYPE_STD__ISNAN
-
-/* Define if your system has a prototype for std::vfprintf in cstdarg cstdio.
-   */
-#undef HAVE_PROTOTYPE_STD__VFPRINTF
-
 /* Define if your system has a prototype for std::vsnprintf in cstdarg cstdio.
    */
 #undef HAVE_PROTOTYPE_STD__VSNPRINTF
@@ -567,39 +490,21 @@ typedef unsigned short ushort;
 /* Define to 1 if you have the `readdir_r' function. */
 #undef HAVE_READDIR_R
 
-/* Define to 1 if you have the `rindex' function. */
-#undef HAVE_RINDEX
-
 /* Define to 1 if you have the <semaphore.h> header file. */
 #undef HAVE_SEMAPHORE_H
 
 /* Define to 1 if you have the `setuid' function. */
 #undef HAVE_SETUID
 
-/* Define to 1 if the system has the type `sigjmp_buf'. */
-#undef HAVE_SIGJMP_BUF
-
 /* Define to 1 if you have the `sleep' function. */
 #undef HAVE_SLEEP
 
-/* Define to 1 if you have the `stat' function. */
-#undef HAVE_STAT
-
-/* Define if the compiler supports static_assert. */
-#undef HAVE_STATIC_ASSERT
-
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
 /* Define to 1 if you have the <stdlib.h> header file. */
 #undef HAVE_STDLIB_H
 
-/* Define if ANSI standard C++ includes use std namespace. */
-#undef HAVE_STD_NAMESPACE
-
-/* Define if the compiler supports std::nothrow. */
-#undef HAVE_STD__NOTHROW
-
 /* Define if STL's algorithm should be used. */
 #undef HAVE_STL_ALGORITHM
 
@@ -633,9 +538,6 @@ typedef unsigned short ushort;
 /* Define if STL's vector should be used. */
 #undef HAVE_STL_VECTOR
 
-/* Define to 1 if you have the `strdup' function. */
-#undef HAVE_STRDUP
-
 /* Define to 1 if you have the <strings.h> header file. */
 #undef HAVE_STRINGS_H
 
@@ -667,9 +569,6 @@ typedef unsigned short ushort;
    */
 #undef HAVE_SYS_DIR_H
 
-/* Define to 1 if you have the <sys/errno.h> header file. */
-#undef HAVE_SYS_ERRNO_H
-
 /* Define to 1 if you have the <sys/file.h> header file. */
 #undef HAVE_SYS_FILE_H
 
@@ -758,9 +657,6 @@ typedef unsigned short ushort;
 /* Define if variable-length arrays are supported in C. */
 #undef HAVE_VLA
 
-/* Define to 1 if you have the `vsnprintf' function. */
-#undef HAVE_VSNPRINTF
-
 /* Define to 1 if you have the `waitpid' function. */
 #undef HAVE_WAITPID
 
@@ -812,21 +708,12 @@ typedef unsigned short ushort;
 /* Define as the return type of signal handlers (`int' or `void'). */
 #undef RETSIGTYPE
 
-/* The size of `double', as computed by sizeof. */
-#undef SIZEOF_DOUBLE
-
-/* The size of `float', as computed by sizeof. */
-#undef SIZEOF_FLOAT
-
 /* The size of `int', as computed by sizeof. */
 #undef SIZEOF_INT
 
 /* The size of `long', as computed by sizeof. */
 #undef SIZEOF_LONG
 
-/* The size of `short', as computed by sizeof. */
-#undef SIZEOF_SHORT
-
 /* The size of `void *', as computed by sizeof. */
 #undef SIZEOF_VOID_P
 
@@ -918,9 +805,6 @@ typedef unsigned short ushort;
 # undef __CHAR_UNSIGNED__
 #endif
 
-/* Define to int if undefined. */
-#undef socklen_t
-
 #if defined(HAVE_CXX11) && defined(__cplusplus) && __cplusplus < 201103L
 #error \
 DCMTK was configured to use C++11 features, but your compiler does not or was not configured to provide them.
index cccc5d506f63cd74eb2b3a8c60c7fe9a3d21467d..19f19c930154af7b4aff0c9a41efbfa931507c2d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, OFFIS e.V.
+ *  Copyright (C) 2015-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -46,37 +46,26 @@ struct dcmtk_config_math
 {
   static inline OFBool isnan( float f )
   {
-#ifdef HAVE_PROTOTYPE_STD__ISNAN
     return STD_NAMESPACE isnan(f);
-#else
-    return ::isnan(f);
-#endif
   }
 
   static inline OFBool isnan( double d )
   {
-#ifdef HAVE_PROTOTYPE_STD__ISNAN
     return STD_NAMESPACE isnan(d);
-#else
-    return ::isnan(d);
-#endif
   }
 
   static inline OFBool isinf( float f )
   {
-#ifdef HAVE_PROTOTYPE_STD__ISINF
     return STD_NAMESPACE isinf( f );
-#else
-    return ::isinf( f );
-#endif
   }
 
   static inline OFBool isinf( double d )
   {
-#ifdef HAVE_PROTOTYPE_STD__ISINF
     return STD_NAMESPACE isinf( d );
-#else
-    return ::isinf( d );
-#endif
+  }
+
+  static inline double sqrt( double d )
+  {
+    return STD_NAMESPACE sqrt(d);
   }
 };
index cd5b43441930dce2a2efa0bd8b350c31c02c9920..6c9ca95f5500d9cabd92f16bb670ad4a07f58e73 100644 (file)
@@ -1 +1 @@
-oficonv ofstd oflog dcmdata dcmiod dcmfg dcmseg dcmimgle dcmimage dcmjpeg dcmjpls dcmtls dcmnet dcmsr dcmsign dcmwlm dcmqrdb dcmpstat dcmrt dcmtract dcmpmap dcmect dcmapps
+oficonv ofstd oflog dcmdata dcmimgle dcmimage dcmjpeg dcmjpls dcmtls dcmnet dcmsr dcmsign dcmwlm dcmqrdb dcmrt dcmiod dcmpstat dcmfg dcmseg dcmtract dcmpmap dcmect dcmapps
\ No newline at end of file
index 88b1ee3395d7a8f32f5861633ed951ca1809b133..249f20825010d236beaa749e810b9ecb343efa78 100644 (file)
@@ -4,4 +4,4 @@ foreach(PROGRAM dcm2img)
 endforeach()
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcm2img dcmjpeg dcmjpls dcmimage dcmimgle dcmdata oflog oficonv ofstd)
+DCMTK_TARGET_LINK_MODULES(dcm2img dcmjpeg dcmjpls)
index aee64c3c4c6ace1a616e671f780a4efd2126ee1b..9acb1961ed6dc6514b07a86871a57d0e4a021a9e 100644 (file)
@@ -174,6 +174,22 @@ color space conversion (JPEG compressed images only):
   +cn   --conv-never
           never convert color space
 
+bits stored:
+
+  +bs  --bits-stored-fix
+         correct inconsistent bits stored value (default)
+
+  # If the value of BitsStored in the compressed bitstream is smaller
+  # than the value in the DICOM dataset, update the value in the dataset
+  # (JPEG compressed images only)
+
+  -bs  --bits-stored-keep
+         preserve inconsistent bits stored value
+
+  # Keep the value of BitsStored even if inconsistent with the
+  # compressed bitstream. This may help in correctly decoding some
+  # defective images JPEG compressed images only)
+
 workaround options for incorrect encodings (JPEG compressed images only):
 
   +w6   --workaround-pred6
@@ -598,6 +614,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcm2img_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index eae28c89605a69ee9acc1310b2cb1f202acafd9f..51dd903458f8f838011eee3941abcd1b10e5a3c5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -59,9 +59,7 @@
 #endif
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>                       /*  for O_BINARY */
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>                          /* for setmode() on Windows */
 #endif
@@ -640,7 +638,7 @@ static E_FileType getFileTypeByExtension(const char *fname)
     // no filename extension, return BMP as the default for files
     if (pos == OFString_npos)
     {
-        OFLOG_WARN(dcm2imgLogger, "no filename extension specified, writing BMP file.");
+        OFLOG_WARN(dcm2imgLogger, "no filename extension specified, writing BMP file");
         return EFT_BMP;
     }
 
@@ -669,7 +667,7 @@ static E_FileType getFileTypeByExtension(const char *fname)
 #endif /* WITH_OPENJPEG */
 #endif /* BUILD_DCM2IMG_AS_DCM2KIMG */
 
-    OFLOG_WARN(dcm2imgLogger, "unsupported filename extension '" << extension << "', writing BMP file.");
+    OFLOG_WARN(dcm2imgLogger, "unsupported filename extension '" << extension << "', writing BMP file");
     return EFT_BMP;
 }
 
@@ -678,6 +676,8 @@ int main(int argc, char *argv[])
     OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, consoleDescription, rcsid);
     OFCommandLine cmd;
 
+    int exitCode = 0;
+
     E_FileReadMode      opt_readMode = ERM_autoDetect;    /* default: fileformat or dataset */
     E_TransferSyntax    opt_transferSyntax = EXS_Unknown; /* default: xfer syntax recognition */
 
@@ -737,6 +737,7 @@ int main(int argc, char *argv[])
     OFBool              opt_predictor6WorkaroundEnable = OFFalse;
     OFBool              opt_cornellWorkaroundEnable = OFFalse;
     OFBool              opt_forceSingleFragmentPerFrame = OFFalse;
+    OFBool              opt_preserveBitsStored = OFFalse;
 
     // JPEG-LS parameters
     OFBool              opt_true_lossless = OFFalse;
@@ -767,8 +768,7 @@ int main(int argc, char *argv[])
 
     int                 opt_imageInfo = 0;                /* default: no info */
     int                 opt_suppressOutput = 0;           /* default: create output */
-    E_FileType          opt_fileType = EFT_default;
-                                                          /* (binary for file output and ASCII for stdout) */
+    E_FileType          opt_fileType = EFT_default;       /* default: auto */
     OFCmdUnsignedInt    opt_fileBits = 0;                 /* default: 0 */
     const char *        opt_ifname = NULL;
     const char *        opt_ofname = NULL;
@@ -846,6 +846,10 @@ int main(int argc, char *argv[])
       cmd.addOption("--conv-always",        "+ca",     "always convert YCbCr to RGB");
       cmd.addOption("--conv-never",         "+cn",     "never convert color space");
 
+     cmd.addSubGroup("bits stored:");
+      cmd.addOption("--bits-stored-fix",     "+bs",    "correct inconsistent bits stored value (default)");
+      cmd.addOption("--bits-stored-keep",    "-bs",    "preserve inconsistent bits stored value");
+
      cmd.addSubGroup("workaround options for incorrect encodings (JPEG compressed images only):");
       cmd.addOption("--workaround-pred6",    "+w6",    "enable workaround for JPEG lossless images\nwith overflow in predictor 6");
       cmd.addOption("--workaround-incpl",    "+wi",    "enable workaround for incomplete JPEG data");
@@ -1094,9 +1098,15 @@ int main(int argc, char *argv[])
         if (cmd.findOption("--check-lut-depth"))
             opt_compatibilityMode |= CIF_CheckLutBitDepth;
         if (cmd.findOption("--ignore-mlut-depth"))
+        {
+            app.checkConflict("--ignore-mlut-depth", "--check-lut-depth", (opt_compatibilityMode & CIF_CheckLutBitDepth) > 0);
             opt_compatibilityMode |= CIF_IgnoreModalityLutBitDepth;
+        }
         if (cmd.findOption("--ignore-vlut-depth"))
+        {
+            app.checkConflict("--ignore-vlut-depth", "--check-lut-depth", (opt_compatibilityMode & CIF_CheckLutBitDepth) > 0);
             opt_ignoreVoiLutDepth = OFTrue;
+        }
 
         /* image processing options: frame selection */
 
@@ -1212,6 +1222,11 @@ int main(int argc, char *argv[])
             opt_decompCSconversion = EDC_never;
         cmd.endOptionBlock();
 
+        cmd.beginOptionBlock();
+        if (cmd.findOption("--bits-stored-fix")) opt_preserveBitsStored = OFFalse;
+        if (cmd.findOption("--bits-stored-keep")) opt_preserveBitsStored = OFTrue;
+        cmd.beginOptionBlock();
+
         if (cmd.findOption("--workaround-pred6")) opt_predictor6WorkaroundEnable = OFTrue;
         if (cmd.findOption("--workaround-incpl")) opt_forceSingleFragmentPerFrame = OFTrue;
         if (cmd.findOption("--workaround-cornell")) opt_cornellWorkaroundEnable = OFTrue;
@@ -1592,9 +1607,7 @@ int main(int argc, char *argv[])
             opt_fileType = EFT_JPLS;
 #ifdef BUILD_DCM2IMG_AS_DCM2KIMG
         if (cmd.findOption("--write-jp2k-cs"))
-        {
             opt_fileType = EFT_JP2K_CS;
-        }
 #ifdef WITH_OPENJPEG
         if (cmd.findOption("--write-jp2k"))
         {
@@ -1617,8 +1630,8 @@ int main(int argc, char *argv[])
         if (cmd.findOption("--write-pastel-pnm"))
             opt_fileType = EFT_PastelPNM;
 #endif
-        if (opt_ofname && (opt_fileType == EFT_default|| cmd.findOption("--write-auto")))
-            opt_fileType = getFileTypeByExtension(opt_ofname);
+        if (cmd.findOption("--write-auto"))
+            opt_fileType = EFT_default;
         cmd.endOptionBlock();
     }
 
@@ -1632,8 +1645,13 @@ int main(int argc, char *argv[])
             << DCM_DICT_ENVIRONMENT_VARIABLE);
     }
 
-    if (opt_suppressOutput && opt_ofname)
-        OFLOG_WARN(dcm2imgLogger, "ignoring parameter bitmap-out because of option --no-output");
+    if (opt_ofname)
+    {
+        if (opt_suppressOutput)
+            OFLOG_WARN(dcm2imgLogger, "ignoring parameter bitmap-out because of option --no-output");
+        else if (opt_fileType == EFT_default)
+            opt_fileType = getFileTypeByExtension(opt_ofname);
+    }
 
     OFLOG_INFO(dcm2imgLogger, "reading DICOM file: " << opt_ifname);
 
@@ -1643,7 +1661,7 @@ int main(int argc, char *argv[])
     // register JPEG decompression codecs
     DJDecoderRegistration::registerCodecs(opt_decompCSconversion, EUC_default,
         EPC_default, opt_predictor6WorkaroundEnable, opt_cornellWorkaroundEnable,
-        opt_forceSingleFragmentPerFrame);
+        opt_forceSingleFragmentPerFrame, opt_preserveBitsStored);
 
     // register JPEG-LS decompression codecs
     DJLSDecoderRegistration::registerCodecs();
@@ -1653,32 +1671,39 @@ int main(int argc, char *argv[])
     if (opt_use_openjpeg)
     {
         // register global OpenJPEG decompression codecs
-        O2DecoderRegistration::registerCodecs(EJ2UC_default, EJ2PC_restore, OFstatic_cast(int, openJPEGNumThreads), 0 /* decoder flags */, OFTrue, OFTrue);
+        O2DecoderRegistration::registerCodecs(EJ2UC_default, EJ2PC_restore, OFstatic_cast(int, openJPEGNumThreads), 0 /* decoder flags */, OFTrue, OFTrue, opt_preserveBitsStored);
     }
     else
     {
         // register global JasPer decompression codecs
-        D2DecoderRegistration::registerCodecs();
+        D2DecoderRegistration::registerCodecs(EJ2UC_default, EJ2PC_restore, OFTrue, OFTrue, opt_preserveBitsStored);
     }
 #else /* WITH_OPENJPEG */
     // register global JasPer decompression codecs
-    D2DecoderRegistration::registerCodecs();
+    D2DecoderRegistration::registerCodecs(EJ2UC_default, EJ2PC_restore, OFTrue, OFTrue, opt_preserveBitsStored);
 #endif /* WITH_OPENJPEG */
 #endif /* BUILD_DCM2IMG_AS_DCM2KIMG */
 
+    DcmDataset *dataset = NULL;
+    DicomImage *di = NULL;
+    DiDisplayFunction *disp = NULL;
+    E_TransferSyntax xfer = EXS_Unknown;
+
     DcmFileFormat *dfile = new DcmFileFormat();
     OFCondition cond = dfile->loadFile(opt_ifname, opt_transferSyntax, EGL_withoutGL, DCM_MaxReadLength, opt_readMode);
 
     if (cond.bad())
     {
         OFLOG_FATAL(dcm2imgLogger, cond.text() << ": reading file: " << opt_ifname);
-        return 1;
+        delete dfile;
+        exitCode = 1;
+        goto cleanup;
     }
 
     OFLOG_INFO(dcm2imgLogger, "preparing pixel data");
 
-    DcmDataset *dataset = dfile->getDataset();
-    E_TransferSyntax xfer = dataset->getOriginalXfer();
+    dataset = dfile->getDataset();
+    xfer = dataset->getOriginalXfer();
 
     Sint32 frameCount;
     if (dataset->findAndGetSint32(DCM_NumberOfFrames, frameCount).bad())
@@ -1694,21 +1719,22 @@ int main(int argc, char *argv[])
         opt_compatibilityMode |= CIF_UsePartialAccessToPixelData;
     }
 
-    DicomImage *di = new DicomImage(dfile, xfer, opt_compatibilityMode, opt_frame - 1, opt_frameCount);
+    di = new DicomImage(dfile, xfer, opt_compatibilityMode, opt_frame - 1, opt_frameCount);
     if (di == NULL)
     {
         OFLOG_FATAL(dcm2imgLogger, "Out of memory");
-        return 1;
+        exitCode = 1;
+        goto cleanup;
     }
 
     if (di->getStatus() != EIS_Normal)
     {
         OFLOG_FATAL(dcm2imgLogger, DicomImage::getString(di->getStatus()));
-        return 1;
+        exitCode = 1;
+        goto cleanup;
     }
 
     /* create & set display function */
-    DiDisplayFunction *disp = NULL;
     if (!opt_displayFile.empty())
     {
         if (opt_displayFunction == 1)
@@ -1749,14 +1775,19 @@ int main(int argc, char *argv[])
         if (opt_frame != di->getFirstFrame() + 1)
         {
             OFLOG_FATAL(dcm2imgLogger, "cannot select frame " << opt_frame << ", invalid frame number");
-            return 1;
+            exitCode = 1;
+            goto cleanup;
         }
 
         /* convert to grayscale if image is not monochrome */
         if ((opt_convertToGrayscale) && (!di->isMonochrome()))
         {
             di = convertToGrayscale(di);
-            if (di == NULL) return 1;
+            if (di == NULL)
+            {
+                exitCode = 1;
+                goto cleanup;
+            }
         }
 
         /* process overlay parameters */
@@ -1766,7 +1797,11 @@ int main(int argc, char *argv[])
         int result = processVOIParameters(di, opt_windowType, opt_windowParameter,
             opt_windowCenter, opt_windowWidth, opt_voiFunction, opt_ignoreVoiLutDepth,
             opt_roiLeft, opt_roiTop, opt_roiWidth, opt_roiHeight);
-        if (result) return result;
+        if (result)
+        {
+            exitCode = result;
+            goto cleanup;
+        }
 
         /* process presentation LUT parameters */
         processPLUTParameters(di, opt_presShape);
@@ -1782,7 +1817,11 @@ int main(int argc, char *argv[])
         /* perform clipping */
         di = performClipping(di, opt_useClip, opt_scaleType, opt_left,
              opt_top, opt_width, opt_height);
-        if (di == NULL) return 1;
+        if (di == NULL)
+        {
+            exitCode = 1;
+            goto cleanup;
+        }
 
         /* perform rotation */
         performRotation(di, opt_rotateDegree);
@@ -1794,7 +1833,11 @@ int main(int argc, char *argv[])
         di = performScaling(di, opt_useClip, opt_scaleType, opt_left, opt_top,
              opt_width, opt_height, opt_scale_factor, opt_scale_size,
              opt_useInterpolation, opt_useAspectRatio);
-        if (di == NULL) return 1;
+        if (di == NULL)
+        {
+            exitCode = 1;
+            goto cleanup;
+        }
 
         /* write selected frame(s) to file */
 
@@ -1841,7 +1884,8 @@ int main(int argc, char *argv[])
                 if (ofile == NULL)
                 {
                     OFLOG_FATAL(dcm2imgLogger, "cannot create file " << ofname);
-                    return 1;
+                    exitCode = 1;
+                    goto cleanup;
                 }
             } else {
                 /* output to stdout */
@@ -1991,20 +2035,25 @@ int main(int argc, char *argv[])
             {
                 if (fclose(ofile))
                 {
-                    OFLOG_FATAL(dcm2imgLogger, "Error while closing file, content may be incomplete.");
-                    return 1;
+                    OFLOG_FATAL(dcm2imgLogger, "error while closing file, content may be incomplete");
+                    exitCode = 1;
+                    goto cleanup;
                 }
             }
             if (!result)
             {
                 OFLOG_FATAL(dcm2imgLogger, "cannot write frame");
-                return 1;
+                exitCode = 1;
+                goto cleanup;
             }
         }
     }
 
     /* done, now cleanup. */
     OFLOG_INFO(dcm2imgLogger, "cleaning up memory");
+
+  cleanup:
+
     delete di;
     delete disp;
 
@@ -2026,5 +2075,5 @@ int main(int argc, char *argv[])
 #endif /* WITH_OPENJPEG */
 #endif /* BUILD_DCM2IMG_AS_DCM2KIMG */
 
-    return 0;
+    return exitCode;
 }
index 72caa400d99faf3cdddbd5912ea78ae360392a2f..4ba9859b57a88e280a19f16759893f31ebf3a653 100644 (file)
@@ -2,19 +2,20 @@
 include_directories(${LIBXML_INCDIR})
 
 # declare executables
-foreach(PROGRAM dcm2xml dcmconv dcmcrle dcmdrle dcmdump dcmftest dcmgpdir dump2dcm xml2dcm stl2dcm pdf2dcm dcm2pdf img2dcm dcm2json cda2dcm dcm2cda)
+foreach(PROGRAM dcm2xml dcmconv dcmcrle dcmdrle dcmdump dcmftest dcmgpdir dump2dcm xml2dcm stl2dcm pdf2dcm dcm2pdf img2dcm dcm2json cda2dcm dcm2cda json2dcm dcmencap dcmdecap)
   DCMTK_ADD_EXECUTABLE(${PROGRAM} ${PROGRAM}.cc)
 endforeach()
+
 DCMTK_ADD_EXECUTABLE(dcmodify
   dcmodify.cc
   mdfconen.cc
   mdfdsman.cc)
 
 # make sure executables are linked to the corresponding libraries
-foreach(PROGRAM dcm2xml dcmconv dcmcrle dcmdrle dcmdump dcmgpdir dcmodify dump2dcm xml2dcm stl2dcm pdf2dcm dcm2pdf img2dcm dcm2json cda2dcm dcm2cda)
-  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmdata oflog ofstd)
+foreach(PROGRAM dcm2xml dcmconv dcmcrle dcmdrle dcmdump dcmgpdir dcmodify dump2dcm stl2dcm pdf2dcm dcm2pdf dcm2json json2dcm cda2dcm dcm2cda dcmencap dcmdecap)
+  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmdata)
 endforeach()
 
 DCMTK_TARGET_LINK_MODULES(dcmftest ofstd)
-DCMTK_TARGET_LINK_MODULES(img2dcm i2d dcmdata)
-DCMTK_TARGET_LINK_MODULES(xml2dcm dcmxml dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(img2dcm i2d)
+DCMTK_TARGET_LINK_MODULES(xml2dcm dcmxml)
index b1823b727803e2ab366d07a1b1eac6b64e9cfc28..ed03832172f0f3defdddad1513cac7b514766905 100644 (file)
@@ -1,96 +1,28 @@
 cda2dcm.o: cda2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
- ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
- ../../oflog/include/dcmtk/oflog/oflog.h \
- ../../oflog/include/dcmtk/oflog/logger.h \
- ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstub.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../oflog/include/dcmtk/oflog/config/defines.h \
- ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
- ../../oflog/include/dcmtk/oflog/loglevel.h \
- ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../oflog/include/dcmtk/oflog/tchar.h \
- ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
- ../../oflog/include/dcmtk/oflog/appender.h \
- ../../ofstd/include/dcmtk/ofstd/ofmem.h \
- ../../ofstd/include/dcmtk/ofstd/ofutil.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
- ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
- ../../oflog/include/dcmtk/oflog/layout.h \
- ../../oflog/include/dcmtk/oflog/streams.h \
- ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
- ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
- ../../oflog/include/dcmtk/oflog/spi/filter.h \
- ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
- ../../oflog/include/dcmtk/oflog/spi/logfact.h \
- ../../oflog/include/dcmtk/oflog/logmacro.h \
- ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
- ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcswap.h \
- ../include/dcmtk/dcmdata/dcerror.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcistrma.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcostrma.h ../include/dcmtk/dcmdata/dcuid.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcdicent.h \
- ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcdict.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dcelem.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcsequen.h \
- ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcdicdir.h \
- ../../ofstd/include/dcmtk/ofstd/ofmap.h \
- ../include/dcmtk/dcmdata/dcdirrec.h ../include/dcmtk/dcmdata/dcvrulup.h \
- ../include/dcmtk/dcmdata/dcvrul.h ../include/dcmtk/dcmdata/dcpixseq.h \
- ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcbytstr.h \
- ../include/dcmtk/dcmdata/dcvrae.h ../include/dcmtk/dcmdata/dcvras.h \
- ../include/dcmtk/dcmdata/dcvrcs.h ../include/dcmtk/dcmdata/dcvrda.h \
- ../../ofstd/include/dcmtk/ofstd/ofdate.h \
- ../include/dcmtk/dcmdata/dcvrds.h ../include/dcmtk/dcmdata/dcvrdt.h \
- ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
- ../../ofstd/include/dcmtk/ofstd/oftime.h \
- ../include/dcmtk/dcmdata/dcvris.h ../include/dcmtk/dcmdata/dcvrtm.h \
- ../include/dcmtk/dcmdata/dcvrui.h ../include/dcmtk/dcmdata/dcvrur.h \
- ../include/dcmtk/dcmdata/dcchrstr.h ../include/dcmtk/dcmdata/dcvrlo.h \
- ../include/dcmtk/dcmdata/dcvrlt.h ../include/dcmtk/dcmdata/dcvrpn.h \
- ../include/dcmtk/dcmdata/dcvrsh.h ../include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmdata/dcvruc.h ../include/dcmtk/dcmdata/dcvrut.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpixel.h \
- ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcovlay.h \
- ../include/dcmtk/dcmdata/dcvrat.h ../include/dcmtk/dcmdata/dcvrss.h \
- ../include/dcmtk/dcmdata/dcvrus.h ../include/dcmtk/dcmdata/dcvrsl.h \
- ../include/dcmtk/dcmdata/dcvrsv.h ../include/dcmtk/dcmdata/dcvruv.h \
- ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
- ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
- ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcencdoc.h \
- ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
- ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
- ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
- ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
- ../../ofstd/include/dcmtk/ofstd/ofexit.h
+ ../../ofstd/include/dcmtk/ofstd/oferror.h
 dcm2cda.o: dcm2cda.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstub.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h
+dcm2json.o: dcm2json.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -176,14 +108,19 @@ dcm2cda.o: dcm2cda.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
  ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
  ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h \
+ ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcjson.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
  ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcistrmz.h
-dcm2json.o: dcm2json.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
+dcm2pdf.o: dcm2pdf.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstub.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h
+dcm2xml.o: dcm2xml.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -269,14 +206,14 @@ dcm2json.o: dcm2json.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
  ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
  ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcjson.h \
+ ../include/dcmtk/dcmdata/cmdlnarg.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
  ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
  ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
-dcm2pdf.o: dcm2pdf.cc ../../config/include/dcmtk/config/osconfig.h \
+dcmconv.o: dcmconv.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -368,8 +305,9 @@ dcm2pdf.o: dcm2pdf.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcistrmz.h
-dcm2xml.o: dcm2xml.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcostrmz.h ../include/dcmtk/dcmdata/dcistrmz.h \
+ ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
+dcmcrle.o: dcmcrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -461,30 +399,49 @@ dcm2xml.o: dcm2xml.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
-dcmconv.o: dcmconv.cc ../../config/include/dcmtk/config/osconfig.h \
- ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
- ../../oflog/include/dcmtk/oflog/oflog.h \
- ../../oflog/include/dcmtk/oflog/logger.h \
- ../../oflog/include/dcmtk/oflog/config.h \
+ ../include/dcmtk/dcmdata/dcrleerg.h
+dcmdecap.o: dcmdecap.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcistrmz.h \
+ ../include/dcmtk/dcmdata/dcistrma.h ../include/dcmtk/dcmdata/dcxfer.h \
+ ../include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
  ../../oflog/include/dcmtk/oflog/config/defines.h \
  ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
  ../../oflog/include/dcmtk/oflog/loglevel.h \
  ../../ofstd/include/dcmtk/ofstd/ofvector.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../oflog/include/dcmtk/oflog/tstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../oflog/include/dcmtk/oflog/tchar.h \
  ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
- ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
  ../../oflog/include/dcmtk/oflog/layout.h \
  ../../oflog/include/dcmtk/oflog/streams.h \
@@ -496,67 +453,19 @@ dcmconv.o: dcmconv.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcswap.h \
- ../include/dcmtk/dcmdata/dcerror.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcistrma.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcostrma.h ../include/dcmtk/dcmdata/dcuid.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
+ ../include/dcmtk/dcmdata/dcdocdec.h ../include/dcmtk/dcmdata/dcfilefo.h \
+ ../include/dcmtk/dcmdata/dcsequen.h ../include/dcmtk/dcmdata/dcelem.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
+ ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcdicent.h \
- ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcdict.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dcelem.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcsequen.h \
- ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcdicdir.h \
- ../../ofstd/include/dcmtk/ofstd/ofmap.h \
- ../include/dcmtk/dcmdata/dcdirrec.h ../include/dcmtk/dcmdata/dcvrulup.h \
- ../include/dcmtk/dcmdata/dcvrul.h ../include/dcmtk/dcmdata/dcpixseq.h \
- ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcbytstr.h \
- ../include/dcmtk/dcmdata/dcvrae.h ../include/dcmtk/dcmdata/dcvras.h \
- ../include/dcmtk/dcmdata/dcvrcs.h ../include/dcmtk/dcmdata/dcvrda.h \
- ../../ofstd/include/dcmtk/ofstd/ofdate.h \
- ../include/dcmtk/dcmdata/dcvrds.h ../include/dcmtk/dcmdata/dcvrdt.h \
- ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
- ../../ofstd/include/dcmtk/ofstd/oftime.h \
- ../include/dcmtk/dcmdata/dcvris.h ../include/dcmtk/dcmdata/dcvrtm.h \
- ../include/dcmtk/dcmdata/dcvrui.h ../include/dcmtk/dcmdata/dcvrur.h \
- ../include/dcmtk/dcmdata/dcchrstr.h ../include/dcmtk/dcmdata/dcvrlo.h \
- ../include/dcmtk/dcmdata/dcvrlt.h ../include/dcmtk/dcmdata/dcvrpn.h \
- ../include/dcmtk/dcmdata/dcvrsh.h ../include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmdata/dcvruc.h ../include/dcmtk/dcmdata/dcvrut.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpixel.h \
- ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcovlay.h \
- ../include/dcmtk/dcmdata/dcvrat.h ../include/dcmtk/dcmdata/dcvrss.h \
- ../include/dcmtk/dcmdata/dcvrus.h ../include/dcmtk/dcmdata/dcvrsl.h \
- ../include/dcmtk/dcmdata/dcvrsv.h ../include/dcmtk/dcmdata/dcvruv.h \
- ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
- ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
- ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h \
- ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
- ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
- ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
- ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
- ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcostrmz.h ../include/dcmtk/dcmdata/dcistrmz.h \
- ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
-dcmcrle.o: dcmcrle.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcdict.h \
+ ../include/dcmtk/dcmdata/dchashdi.h
+dcmdrle.o: dcmdrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -648,8 +557,10 @@ dcmcrle.o: dcmcrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcrleerg.h
-dcmdrle.o: dcmdrle.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcrledrg.h
+dcmdump.o: dcmdump.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -657,7 +568,6 @@ dcmdrle.o: dcmdrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../oflog/include/dcmtk/oflog/config/defines.h \
  ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
  ../../oflog/include/dcmtk/oflog/loglevel.h \
@@ -665,7 +575,6 @@ dcmdrle.o: dcmdrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../oflog/include/dcmtk/oflog/tstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../oflog/include/dcmtk/oflog/tchar.h \
  ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
@@ -741,30 +650,48 @@ dcmdrle.o: dcmdrle.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcrledrg.h
-dcmdump.o: dcmdump.cc ../../config/include/dcmtk/config/osconfig.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../include/dcmtk/dcmdata/dcistrmz.h \
+ ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
+dcmencap.o: dcmencap.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcencdoc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcfilefo.h \
+ ../include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../include/dcmtk/dcmdata/dcelem.h ../include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
+ ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
  ../../oflog/include/dcmtk/oflog/config.h \
- ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
- ../../ofstd/include/dcmtk/ofstd/ofcast.h \
- ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../../oflog/include/dcmtk/oflog/config/defines.h \
  ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
  ../../oflog/include/dcmtk/oflog/loglevel.h \
  ../../ofstd/include/dcmtk/ofstd/ofvector.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../oflog/include/dcmtk/oflog/tstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../oflog/include/dcmtk/oflog/tchar.h \
  ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
- ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
  ../../oflog/include/dcmtk/oflog/layout.h \
  ../../oflog/include/dcmtk/oflog/streams.h \
@@ -776,66 +703,20 @@ dcmdump.o: dcmdump.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcswap.h \
- ../include/dcmtk/dcmdata/dcerror.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcistrma.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcostrma.h ../include/dcmtk/dcmdata/dcuid.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
+ ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcdicent.h \
- ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcdict.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dcelem.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcsequen.h \
- ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcdicdir.h \
- ../../ofstd/include/dcmtk/ofstd/ofmap.h \
- ../include/dcmtk/dcmdata/dcdirrec.h ../include/dcmtk/dcmdata/dcvrulup.h \
- ../include/dcmtk/dcmdata/dcvrul.h ../include/dcmtk/dcmdata/dcpixseq.h \
- ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcbytstr.h \
- ../include/dcmtk/dcmdata/dcvrae.h ../include/dcmtk/dcmdata/dcvras.h \
- ../include/dcmtk/dcmdata/dcvrcs.h ../include/dcmtk/dcmdata/dcvrda.h \
- ../../ofstd/include/dcmtk/ofstd/ofdate.h \
- ../include/dcmtk/dcmdata/dcvrds.h ../include/dcmtk/dcmdata/dcvrdt.h \
- ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
- ../../ofstd/include/dcmtk/ofstd/oftime.h \
- ../include/dcmtk/dcmdata/dcvris.h ../include/dcmtk/dcmdata/dcvrtm.h \
- ../include/dcmtk/dcmdata/dcvrui.h ../include/dcmtk/dcmdata/dcvrur.h \
- ../include/dcmtk/dcmdata/dcchrstr.h ../include/dcmtk/dcmdata/dcvrlo.h \
- ../include/dcmtk/dcmdata/dcvrlt.h ../include/dcmtk/dcmdata/dcvrpn.h \
- ../include/dcmtk/dcmdata/dcvrsh.h ../include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmdata/dcvruc.h ../include/dcmtk/dcmdata/dcvrut.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpixel.h \
- ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcovlay.h \
- ../include/dcmtk/dcmdata/dcvrat.h ../include/dcmtk/dcmdata/dcvrss.h \
- ../include/dcmtk/dcmdata/dcvrus.h ../include/dcmtk/dcmdata/dcvrsl.h \
- ../include/dcmtk/dcmdata/dcvrsv.h ../include/dcmtk/dcmdata/dcvruv.h \
- ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
- ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
- ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h \
- ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dcpcache.h \
  ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
- ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../include/dcmtk/dcmdata/dcistrmz.h \
- ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
+ ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcuid.h \
+ ../include/dcmtk/dcmdata/dcdict.h ../include/dcmtk/dcmdata/dchashdi.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h
 dcmftest.o: dcmftest.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcmetinf.h ../include/dcmtk/dcmdata/dcitem.h \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
@@ -1130,6 +1011,72 @@ img2dcm.o: img2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/libi2d/i2dplop.h \
  ../include/dcmtk/dcmdata/dcmxml/xml2dcm.h \
  ../include/dcmtk/dcmdata/dcmxml/dcxmldf.h
+json2dcm.o: json2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcdefine.h \
+ ../include/dcmtk/dcmdata/dcostrmz.h ../include/dcmtk/dcmdata/dcostrma.h \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcsequen.h \
+ ../include/dcmtk/dcmdata/dcelem.h ../include/dcmtk/dcmdata/dcobject.h \
+ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dctag.h \
+ ../include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcdeftag.h \
+ ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdict.h \
+ ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcjsonrd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofjsmn.h
 mdfconen.o: mdfconen.cc ../../config/include/dcmtk/config/osconfig.h \
  mdfconen.h ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
@@ -1288,189 +1235,43 @@ mdfdsman.o: mdfdsman.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h
 pdf2dcm.o: pdf2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
- ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
- ../../oflog/include/dcmtk/oflog/oflog.h \
- ../../oflog/include/dcmtk/oflog/logger.h \
- ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstub.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../oflog/include/dcmtk/oflog/config/defines.h \
- ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
- ../../oflog/include/dcmtk/oflog/loglevel.h \
- ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../oflog/include/dcmtk/oflog/tchar.h \
- ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
- ../../oflog/include/dcmtk/oflog/appender.h \
- ../../ofstd/include/dcmtk/ofstd/ofmem.h \
- ../../ofstd/include/dcmtk/ofstd/ofutil.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
- ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
- ../../oflog/include/dcmtk/oflog/layout.h \
- ../../oflog/include/dcmtk/oflog/streams.h \
- ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
- ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
- ../../oflog/include/dcmtk/oflog/spi/filter.h \
- ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
- ../../oflog/include/dcmtk/oflog/spi/logfact.h \
- ../../oflog/include/dcmtk/oflog/logmacro.h \
- ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
- ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcswap.h \
- ../include/dcmtk/dcmdata/dcerror.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcistrma.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcostrma.h ../include/dcmtk/dcmdata/dcuid.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcdicent.h \
- ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcdict.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dcelem.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcsequen.h \
- ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcdicdir.h \
- ../../ofstd/include/dcmtk/ofstd/ofmap.h \
- ../include/dcmtk/dcmdata/dcdirrec.h ../include/dcmtk/dcmdata/dcvrulup.h \
- ../include/dcmtk/dcmdata/dcvrul.h ../include/dcmtk/dcmdata/dcpixseq.h \
- ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcbytstr.h \
- ../include/dcmtk/dcmdata/dcvrae.h ../include/dcmtk/dcmdata/dcvras.h \
- ../include/dcmtk/dcmdata/dcvrcs.h ../include/dcmtk/dcmdata/dcvrda.h \
- ../../ofstd/include/dcmtk/ofstd/ofdate.h \
- ../include/dcmtk/dcmdata/dcvrds.h ../include/dcmtk/dcmdata/dcvrdt.h \
- ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
- ../../ofstd/include/dcmtk/ofstd/oftime.h \
- ../include/dcmtk/dcmdata/dcvris.h ../include/dcmtk/dcmdata/dcvrtm.h \
- ../include/dcmtk/dcmdata/dcvrui.h ../include/dcmtk/dcmdata/dcvrur.h \
- ../include/dcmtk/dcmdata/dcchrstr.h ../include/dcmtk/dcmdata/dcvrlo.h \
- ../include/dcmtk/dcmdata/dcvrlt.h ../include/dcmtk/dcmdata/dcvrpn.h \
- ../include/dcmtk/dcmdata/dcvrsh.h ../include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmdata/dcvruc.h ../include/dcmtk/dcmdata/dcvrut.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpixel.h \
- ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcovlay.h \
- ../include/dcmtk/dcmdata/dcvrat.h ../include/dcmtk/dcmdata/dcvrss.h \
- ../include/dcmtk/dcmdata/dcvrus.h ../include/dcmtk/dcmdata/dcvrsl.h \
- ../include/dcmtk/dcmdata/dcvrsv.h ../include/dcmtk/dcmdata/dcvruv.h \
- ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
- ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
- ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcencdoc.h \
- ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
- ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
- ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
- ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
- ../../ofstd/include/dcmtk/ofstd/ofexit.h
+ ../../ofstd/include/dcmtk/ofstd/oferror.h
 stl2dcm.o: stl2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
- ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
- ../../oflog/include/dcmtk/oflog/oflog.h \
- ../../oflog/include/dcmtk/oflog/logger.h \
- ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstub.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../oflog/include/dcmtk/oflog/config/defines.h \
- ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
- ../../oflog/include/dcmtk/oflog/loglevel.h \
- ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../oflog/include/dcmtk/oflog/tchar.h \
- ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
- ../../oflog/include/dcmtk/oflog/appender.h \
- ../../ofstd/include/dcmtk/ofstd/ofmem.h \
- ../../ofstd/include/dcmtk/ofstd/ofutil.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
- ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
- ../../oflog/include/dcmtk/oflog/layout.h \
- ../../oflog/include/dcmtk/oflog/streams.h \
- ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
- ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
- ../../oflog/include/dcmtk/oflog/spi/filter.h \
- ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
- ../../oflog/include/dcmtk/oflog/spi/logfact.h \
- ../../oflog/include/dcmtk/oflog/logmacro.h \
- ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
- ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcswap.h \
- ../include/dcmtk/dcmdata/dcerror.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcistrma.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcostrma.h ../include/dcmtk/dcmdata/dcuid.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcdicent.h \
- ../include/dcmtk/dcmdata/dchashdi.h ../include/dcmtk/dcmdata/dcdict.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dcelem.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcsequen.h \
- ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcdicdir.h \
- ../../ofstd/include/dcmtk/ofstd/ofmap.h \
- ../include/dcmtk/dcmdata/dcdirrec.h ../include/dcmtk/dcmdata/dcvrulup.h \
- ../include/dcmtk/dcmdata/dcvrul.h ../include/dcmtk/dcmdata/dcpixseq.h \
- ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcbytstr.h \
- ../include/dcmtk/dcmdata/dcvrae.h ../include/dcmtk/dcmdata/dcvras.h \
- ../include/dcmtk/dcmdata/dcvrcs.h ../include/dcmtk/dcmdata/dcvrda.h \
- ../../ofstd/include/dcmtk/ofstd/ofdate.h \
- ../include/dcmtk/dcmdata/dcvrds.h ../include/dcmtk/dcmdata/dcvrdt.h \
- ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
- ../../ofstd/include/dcmtk/ofstd/oftime.h \
- ../include/dcmtk/dcmdata/dcvris.h ../include/dcmtk/dcmdata/dcvrtm.h \
- ../include/dcmtk/dcmdata/dcvrui.h ../include/dcmtk/dcmdata/dcvrur.h \
- ../include/dcmtk/dcmdata/dcchrstr.h ../include/dcmtk/dcmdata/dcvrlo.h \
- ../include/dcmtk/dcmdata/dcvrlt.h ../include/dcmtk/dcmdata/dcvrpn.h \
- ../include/dcmtk/dcmdata/dcvrsh.h ../include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmdata/dcvruc.h ../include/dcmtk/dcmdata/dcvrut.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpixel.h \
- ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcovlay.h \
- ../include/dcmtk/dcmdata/dcvrat.h ../include/dcmtk/dcmdata/dcvrss.h \
- ../include/dcmtk/dcmdata/dcvrus.h ../include/dcmtk/dcmdata/dcvrsl.h \
- ../include/dcmtk/dcmdata/dcvrsv.h ../include/dcmtk/dcmdata/dcvruv.h \
- ../include/dcmtk/dcmdata/dcvrfl.h ../include/dcmtk/dcmdata/dcvrfd.h \
- ../include/dcmtk/dcmdata/dcvrof.h ../include/dcmtk/dcmdata/dcvrod.h \
- ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
- ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcencdoc.h \
- ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
- ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
- ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
- ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
- ../../ofstd/include/dcmtk/ofstd/ofexit.h
+ ../../ofstd/include/dcmtk/ofstd/oferror.h
 xml2dcm.o: xml2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dctk.h ../include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
index 14bc1d34daca86d9a48689445fff5fecb79e05cf..21395b68eb8d7634fdff488f94f2bce4a2635a36 100644 (file)
@@ -25,10 +25,12 @@ LIBDCMXML = -ldcmxml
 
 objs = dcmftest.o dcmconv.o dcmdump.o dump2dcm.o dcmgpdir.o dcm2xml.o \
        xml2dcm.o dcmcrle.o dcmdrle.o dcmodify.o mdfdsman.o mdfconen.o \
-       cda2dcm.o stl2dcm.o pdf2dcm.o dcm2pdf.o dcm2cda.o img2dcm.o dcm2json.o
+       cda2dcm.o stl2dcm.o pdf2dcm.o dcm2pdf.o dcm2cda.o img2dcm.o dcm2json.o \
+       json2dcm.o dcmencap.o dcmdecap.o
 
 progs = dcmftest dcmconv dcmdump dump2dcm dcmgpdir dcm2xml xml2dcm dcmcrle \
-       dcmdrle dcmodify pdf2dcm stl2dcm cda2dcm dcm2pdf dcm2cda img2dcm dcm2json
+       dcmdrle dcmodify pdf2dcm stl2dcm cda2dcm dcm2pdf dcm2cda img2dcm dcm2json \
+       json2dcm dcmencap dcmdecap
 
 
 all: $(progs)
@@ -85,6 +87,15 @@ img2dcm: img2dcm.o
 dcm2json: dcm2json.o
        $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
 
+json2dcm: json2dcm.o
+       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
+
+dcmencap: dcmencap.o
+       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
+
+dcmdecap: dcmdecap.o
+       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
+
 
 install: all
        $(configdir)/mkinstalldirs $(DESTDIR)$(bindir)
index e44ba7adcba170bdec91548ecb8bb77defad61e3..6857ad4e25b0f8129717d02b296c720e682a2fad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2019, OFFIS e.V.
+ *  Copyright (C) 2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *  Module:  dcmdata
  *
- *  Author:  Pedro Arizpe
+ *  Authors: Marco Eichelberg
  *
- *  Purpose: Encapsulate CDA file into a DICOM file
+ *  Purpose: Proxy stub that calls dcmencap
  *
  */
 
-#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first*/
-#include "dcmtk/dcmdata/dctk.h"
-#include "dcmtk/dcmdata/dcencdoc.h"
-#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofstub.h"
+#include "dcmtk/ofstd/ofstd.h"
+#include <cstring>
 
-#ifdef WITH_ZLIB
-#include <zlib.h>        /* for zlibVersion() */
-#endif
-
-#define OFFIS_CONSOLE_APPLICATION "cda2dcm"
-
-static OFLogger cda2dcmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
-
-static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
-OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
-
-int main(int argc, char *argv[])
+int main(int argc, char** argv)
 {
-  OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Encapsulate CDA file into DICOM format", rcsid);
-  OFCommandLine cmd;
-  int errorCode = EXITCODE_NO_ERROR;
-  OFCondition result = EC_Normal;
-  DcmFileFormat fileformat;
-  DcmEncapsulatedDocument encapsulator;
-  OFLOG_TRACE(cda2dcmLogger, "Including necessary options");
-  encapsulator.addCDACommandlineOptions(cmd);
-  OFLOG_TRACE(cda2dcmLogger, "Evaluating command line");
-  prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
-
-  if (app.parseCommandLine(cmd, argc, argv)) {
-    OFLOG_TRACE (cda2dcmLogger, "Checking exclusive options first");
-    if (cmd.hasExclusiveOption())
+    // create an argv array that is one entry larger than the one specified by the user
+    char **my_argv = new char *[argc+2];
+    char filetype[100];
+    OFStandard::strlcpy(filetype, "--filetype-cda", sizeof(filetype));
+
+    // copy arguments, then add file type argument and NULL pointer
+    memcpy(my_argv, argv, argc * sizeof(char *));
+    my_argv[argc] = filetype;
+    my_argv[argc+1] = NULL;
+
+    // call stub
+    int result;
+    if (argc == 1)
     {
-      if (cmd.findOption("--version"))
-      {
-        app.printHeader(OFTrue /*print host identifier*/);
-        COUT << OFendl << "External libraries used: ";
-#ifdef WITH_ZLIB
-        COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
-#else
-        COUT << " none" << OFendl;
-#endif
-        return EXITCODE_NO_ERROR;
-      }
+       // no command line arguments given. Just forward call.
+       result = OFstub_main(argc, argv, "cda2dcm", "dcmencap");
+    }
+    else
+    {
+      // Forward call with additional command line argument.
+      result = OFstub_main(argc+1, my_argv, "cda2dcm", "dcmencap");
     }
-    encapsulator.parseArguments(app, cmd);
-  }
-  //print resource identifier
-  OFLOG_DEBUG(cda2dcmLogger, rcsid << OFendl);
-
-  OFLOG_DEBUG(cda2dcmLogger, "making sure data dictionary is loaded");
-  if (!dcmDataDict.isDictionaryLoaded())
-  {
-    OFLOG_WARN(cda2dcmLogger, "no data dictionary loaded, check environment variable: "
-      << DCM_DICT_ENVIRONMENT_VARIABLE);
-  }
-  OFLOG_TRACE(cda2dcmLogger, "Creating identifiers (and reading series data)");
-  result = encapsulator.createIdentifiers(cda2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_FATAL(cda2dcmLogger, "There was an error while reading the series data");
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  OFLOG_DEBUG(cda2dcmLogger, "Fetching CDA Data");
-  errorCode = encapsulator.getCDAData(encapsulator.getInputFileName().c_str(), cda2dcmLogger);
-  if (errorCode != EXITCODE_NO_ERROR)
-  {
-    OFLOG_ERROR(cda2dcmLogger, "There was a problem with the CDA File");
-    return errorCode;
-  }
-  else
-  {
-  OFLOG_INFO(cda2dcmLogger, "creating encapsulated CDA object");
-  errorCode = encapsulator.insertEncapsulatedDocument(fileformat.getDataset(), cda2dcmLogger);
-  }
-  if (errorCode != EXITCODE_NO_ERROR)
-  {
-    OFLOG_ERROR(cda2dcmLogger, "unable to create CDA encapsulation to DICOM format");
-    return errorCode;
-  }
-  OFLOG_INFO(cda2dcmLogger, "Generating an instance number that is guaranteed to be unique within a series.");
-  result = encapsulator.createHeader(fileformat.getDataset(), cda2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_ERROR(cda2dcmLogger, "unable to create DICOM header: " << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(cda2dcmLogger, "writing encapsulated CDA object as file " << encapsulator.getOutputFileName());
-
-  OFLOG_INFO(cda2dcmLogger, "Check if new output transfer syntax is possible");
-
-  DcmXfer opt_oxferSyn(encapsulator.getTransferSyntax());
-
-  fileformat.getDataset()->chooseRepresentation(encapsulator.getTransferSyntax(), NULL);
-  if (fileformat.getDataset()->canWriteXfer(encapsulator.getTransferSyntax()))
-  {
-    OFLOG_INFO(cda2dcmLogger, "Output transfer syntax " << opt_oxferSyn.getXferName() << " can be written");
-  }
-  else {
-    OFLOG_ERROR(cda2dcmLogger, "No conversion to transfer syntax " << opt_oxferSyn.getXferName() << " possible!");
-    return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-  }
-  OFLOG_INFO(cda2dcmLogger, "Checking for DICOM key overriding");
-  result = encapsulator.applyOverrideKeys(fileformat.getDataset());
-  if (result.bad())
-  {
-    OFLOG_ERROR(cda2dcmLogger, "There was a problem while overriding a key:" << OFendl
-      << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(cda2dcmLogger, "write converted DICOM file with metaheader");
-  result = encapsulator.saveFile(fileformat);
-  if (result.bad())
-  {
-    OFLOG_ERROR(cda2dcmLogger, result.text() << ": writing file: " << encapsulator.getOutputFileName());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-
-  OFLOG_INFO(cda2dcmLogger, "CDA encapsulation successful");
 
-  return EXITCODE_NO_ERROR;
+    // clean up (Windows only, on Posix systems the stub will not return)
+    delete[] my_argv;
+    return result;
 }
index 8a6f7ce5ed00228c3bfd0a292c7a96bfe72baa9b..25767c1998f6757165ec969cb5f3d291c0a16c4c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2023-2024, OFFIS e.V.
+ *  Copyright (C) 2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *  Module:  dcmdata
  *
- *  Author:  Tingyan Xu
+ *  Authors: Marco Eichelberg
  *
- *  Purpose: Extract CDA file from DICOM encapsulated CDA storage object
+ *  Purpose: Proxy stub that calls dcmdecap
  *
  */
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofstub.h"
 
-#include "dcmtk/dcmdata/dctk.h"
-#include "dcmtk/dcmdata/cmdlnarg.h"
-#include "dcmtk/ofstd/ofconapp.h"
-#include "dcmtk/dcmdata/dcuid.h"       /* for dcmtk version name */
-#include "dcmtk/ofstd/ofstd.h"
-#include "dcmtk/dcmdata/dcistrmz.h"    /* for dcmZlibExpectRFC1950Encoding */
-
-#ifdef WITH_ZLIB
-#include <zlib.h>        /* for zlibVersion() */
-#endif
-
-#define OFFIS_CONSOLE_APPLICATION "dcm2cda"
-
-static OFLogger dcm2cdaLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
-
-static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
-OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
-
-#define SHORTCOL 3
-#define LONGCOL 20
-
-void addInputOptions(OFCommandLine& cmd)
-{
-    cmd.addGroup("input options:");
-    cmd.addSubGroup("input file format:");
-        cmd.addOption("--read-file",            "+f", "read file format or data set (default)");
-        cmd.addOption("--read-file-only",       "+fo", "read file format only");
-        cmd.addOption("--read-dataset",         "-f", "read data set without file meta information");
-
-    cmd.addSubGroup("input transfer syntax:");
-        cmd.addOption("--read-xfer-auto",       "-t=", "use TS recognition (default)");
-        cmd.addOption("--read-xfer-detect",     "-td", "ignore TS specified in the file meta header");
-        cmd.addOption("--read-xfer-little",     "-te", "read with explicit VR little endian TS");
-        cmd.addOption("--read-xfer-big",        "-tb", "read with explicit VR big endian TS");
-        cmd.addOption("--read-xfer-implicit",   "-ti", "read with implicit VR little endian TS");
-
-    cmd.addSubGroup("parsing of odd-length attributes:");
-        cmd.addOption("--accept-odd-length",    "+ao", "accept odd length attributes (default)");
-        cmd.addOption("--assume-even-length",   "+ae", "assume real length is one byte larger");
-
-    cmd.addSubGroup("handling of undefined length UN elements:");
-        cmd.addOption("--enable-cp246",         "+ui", "read undefined len UN as implicit VR (default)");
-        cmd.addOption("--disable-cp246",        "-ui", "read undefined len UN as explicit VR");
-
-    cmd.addSubGroup("handling of defined length UN elements:");
-        cmd.addOption("--retain-un",            "-uc", "retain elements as UN (default)");
-        cmd.addOption("--convert-un",           "+uc", "convert to real VR if known");
-
-    cmd.addSubGroup("automatic data correction:");
-        cmd.addOption("--enable-correction",    "+dc", "enable automatic data correction (default)");
-        cmd.addOption("--disable-correction",   "-dc", "disable automatic data correction");
-
-#ifdef WITH_ZLIB
-    cmd.addSubGroup("bitstream format of deflated input:");
-        cmd.addOption("--bitstream-deflated",   "+bd", "expect deflated bitstream (default)");
-        cmd.addOption("--bitstream-zlib",       "+bz", "expect deflated zlib bitstream");
-#endif
-}
-
-void addDCM2CDACommandlineOptions(OFCommandLine& cmd)
-{
-    cmd.setOptionColumns(LONGCOL, SHORTCOL);
-    cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
-
-    cmd.addParam("dcmfile-in", "DICOM input filename (\"-\" for stdin)");
-    cmd.addParam("cdafile-out", "CDA output filename");
-
-    cmd.addGeneralOptions(LONGCOL, SHORTCOL);
-    OFLog::addOptions(cmd);
-    addInputOptions(cmd);
-}
-
-/**
- * function for parsing commandline arguments
- */
-void parseArguments(OFConsoleApplication& app, OFCommandLine& cmd,
-    E_FileReadMode& opt_readMode, E_TransferSyntax& opt_ixfer,
-    const char*& opt_ifname,
-    const char*& opt_ofname
-)
-{
-    cmd.getParam(1, opt_ifname);
-    cmd.getParam(2, opt_ofname);
-
-    OFLog::configureFromCommandLine(cmd, app);
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--read-file"))
-    {
-        opt_readMode = ERM_autoDetect;
-    }
-    if (cmd.findOption("--read-file-only"))
-    {
-        opt_readMode = ERM_fileOnly;
-    }
-    if (cmd.findOption("--read-dataset"))
-    {
-        opt_readMode = ERM_dataset;
-    }
-    cmd.endOptionBlock();
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--read-xfer-auto"))
-    {
-        opt_ixfer = EXS_Unknown;
-    }
-    if (cmd.findOption("--read-xfer-detect"))
-    {
-        dcmAutoDetectDatasetXfer.set(OFTrue);
-    }
-    if (cmd.findOption("--read-xfer-little"))
-    {
-        app.checkDependence("--read-xfer-little", "--read-dataset", opt_readMode == ERM_dataset);
-        opt_ixfer = EXS_LittleEndianExplicit;
-    }
-    if (cmd.findOption("--read-xfer-big"))
-    {
-        app.checkDependence("--read-xfer-big", "--read-dataset", opt_readMode == ERM_dataset);
-        opt_ixfer = EXS_BigEndianExplicit;
-    }
-    if (cmd.findOption("--read-xfer-implicit"))
-    {
-        app.checkDependence("--read-xfer-implicit", "--read-dataset", opt_readMode == ERM_dataset);
-        opt_ixfer = EXS_LittleEndianImplicit;
-    }
-    cmd.endOptionBlock();
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--accept-odd-length"))
-    {
-        dcmAcceptOddAttributeLength.set(OFTrue);
-    }
-    if (cmd.findOption("--assume-even-length"))
-    {
-        dcmAcceptOddAttributeLength.set(OFFalse);
-    }
-    cmd.endOptionBlock();
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--enable-cp246"))
-    {
-        dcmEnableCP246Support.set(OFTrue);
-    }
-    if (cmd.findOption("--disable-cp246"))
-    {
-        dcmEnableCP246Support.set(OFFalse);
-    }
-    cmd.endOptionBlock();
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--retain-un"))
-    {
-        dcmEnableUnknownVRConversion.set(OFFalse);
-    }
-    if (cmd.findOption("--convert-un"))
-    {
-        dcmEnableUnknownVRConversion.set(OFTrue);
-    }
-    cmd.endOptionBlock();
-
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--enable-correction"))
-    {
-        dcmEnableAutomaticInputDataCorrection.set(OFTrue);
-    }
-    if (cmd.findOption("--disable-correction"))
-    {
-        dcmEnableAutomaticInputDataCorrection.set(OFFalse);
-    }
-    cmd.endOptionBlock();
-
-#ifdef WITH_ZLIB
-    cmd.beginOptionBlock();
-    if (cmd.findOption("--bitstream-deflated"))
-    {
-        dcmZlibExpectRFC1950Encoding.set(OFFalse);
-    }
-    if (cmd.findOption("--bitstream-zlib"))
-    {
-        dcmZlibExpectRFC1950Encoding.set(OFTrue);
-    }
-    cmd.endOptionBlock();
-#endif
-}
-
-int main(int argc, char* argv[])
+int main(int argc, char** argv)
 {
-    const char* opt_ifname = NULL;
-    const char* opt_ofname = NULL;
-    E_FileReadMode opt_readMode = ERM_autoDetect;
-    E_TransferSyntax opt_ixfer = EXS_Unknown;
-
-    OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Extract CDA file from DICOM encapsulated CDA", rcsid);
-    OFCommandLine cmd;
-
-    // necessary options
-    addDCM2CDACommandlineOptions(cmd);
-
-    // evaluating command line
-    prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
-    if (app.parseCommandLine(cmd, argc, argv))
-    {
-        // checking exclusive options first
-        if (cmd.hasExclusiveOption())
-        {
-            if (cmd.findOption("--version"))
-            {
-                app.printHeader(OFTrue /*print host identifier*/);
-                COUT << OFendl << "External libraries used:";
-#ifdef WITH_ZLIB
-                COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
-#else
-                COUT << " none" << OFendl;
-#endif
-                return EXITCODE_NO_ERROR;
-            }
-        }
-
-        /* command line parameters and options */
-        parseArguments(app, cmd, opt_readMode, opt_ixfer, opt_ifname, opt_ofname);
-    }
-
-    /* print resource identifier */
-    OFLOG_DEBUG(dcm2cdaLogger, rcsid << OFendl);
-
-    OFLOG_DEBUG(dcm2cdaLogger, "making sure data dictionary is loaded");
-    if (!dcmDataDict.isDictionaryLoaded())
-    {
-        OFLOG_WARN(dcm2cdaLogger, "no data dictionary loaded, check environment variable: "
-            << DCM_DICT_ENVIRONMENT_VARIABLE);
-    }
-
-    // open input file
-    if ((opt_ifname == NULL) || (strlen(opt_ifname) == 0))
-    {
-        OFLOG_ERROR(dcm2cdaLogger, "invalid filename: <empty string>");
-        return EXITCODE_NO_INPUT_FILES;
-    }
-
-    OFCondition cond = EC_Normal;
-
-    DcmFileFormat dfile;
-    DcmDataset* dataset = dfile.getDataset();
-
-    OFLOG_INFO(dcm2cdaLogger, "open input file " << opt_ifname);
-    /* load file to dfile, using given transfer syntax and other variables */
-    cond = dfile.loadFile(opt_ifname, opt_ixfer, EGL_noChange, DCM_MaxReadLength, opt_readMode);
-    if (cond.bad())
-    {
-        OFLOG_ERROR(dcm2cdaLogger, cond.text() << ": reading file: " << opt_ifname);
-        return EXITCODE_CANNOT_READ_INPUT_FILE;
-    }
-
-    /* check SOP */
-    OFString sopClass;
-    cond = dataset->findAndGetOFString(DCM_SOPClassUID, sopClass);
-    if (cond.bad() || sopClass != UID_EncapsulatedCDAStorage)
-    {
-        OFLOG_ERROR(dcm2cdaLogger, "SOPClassUID not of SOP UID_EncapsulatedCDAStorage: " << opt_ifname);
-        return EXITCODE_INVALID_INPUT_FILE;
-    }
-
-    /* get EncapsulatedDocument */
-    Uint8* cdaDocument = NULL;
-    unsigned long int delemlen = 0;
-    cond = dataset->findAndGetUint8Array(DCM_EncapsulatedDocument, (const Uint8*&)cdaDocument, &delemlen);
-    if (cond.bad() || cdaDocument == NULL || delemlen == 0)
-    {
-        OFLOG_ERROR(dcm2cdaLogger, "EncapsulatedDocument missing or has the wrong VR");
-        return EXITCODE_INVALID_INPUT_FILE;
-    }
-
-    /* get and check element Encapsulated Document Length */
-    Uint32 lenElem;
-    cond = dataset->findAndGetUint32(DCM_EncapsulatedDocumentLength, lenElem);
-    /* EncapsulatedDocumentLength Element is invalid or
-    * it does not fit the length of the encapsulated document
-    * (it has to be equal or equal to EncapsulatedDocumentLength -1)
-    */
-    if (cond.bad() || (lenElem != delemlen && lenElem != delemlen - 1))
-    {
-        OFLOG_DEBUG(dcm2cdaLogger, "EncapsulatedDocumentLength missing or invalid, "
-                                "using length of EncapsulatedDocument");
-        lenElem = delemlen;
-        /* Strip pad byte at end of file, if there is one.
-        * CDA documents end with a closing XML tag, optionally followed by whitespace.
-        * If the last character of the file is not a CR ('\r', 13) or LF ('\n', 10), and not the
-        * letter '>', we assume it is either trailing garbage or a pad byte, and remove it.
-        */
-        if (cdaDocument[lenElem - 1] != '\n' && cdaDocument[lenElem - 1] != '\r' && cdaDocument[lenElem - 1] != '>')
-        {
-            OFLOG_DEBUG(dcm2cdaLogger, "removing the pad byte at end of EncapsulatedDocument");
-            --lenElem;
-        }
-    }
-
-    OFLOG_INFO(dcm2cdaLogger, "writing CDA file to " << opt_ofname);
-    FILE* cdafile = fopen(opt_ofname, "wb");
-    if (cdafile == NULL)
-    {
-        OFLOG_ERROR(dcm2cdaLogger, "unable to create file " << opt_ofname);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    if (lenElem != fwrite(cdaDocument, 1, lenElem, cdafile))
-    {
-        OFLOG_ERROR(dcm2cdaLogger, "write error in file " << opt_ofname);
-        fclose(cdafile);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    if(fclose(cdafile))
-    {
-        OFLOG_FATAL(dcm2cdaLogger, "write error in file " << opt_ofname);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    OFLOG_INFO(dcm2cdaLogger, "conversion successful");
-
-    return EXITCODE_NO_ERROR;
+    // call stub. Will not return on Posix systems.
+    return OFstub_main(argc, argv, "dcm2cda", "dcmdecap");
 }
index 83be46baaa411427310d3cefbafef067f91edf71..d4b4dc230cff8c9ad9ae868c1f08160a828eb6c5 100644 (file)
@@ -1,23 +1,23 @@
 /*
-*
-*  Copyright (C) 2016-2022, OFFIS e.V.
-*  All rights reserved.  See COPYRIGHT file for details.
-*
-*  This software and supporting documentation were developed by
-*
-*    OFFIS e.V.
-*    R&D Division Health
-*    Escherweg 2
-*    D-26121 Oldenburg, Germany
-*
-*
-*  Module:  dcmdata
-*
-*  Author:  Sebastian Grallert
-*
-*  Purpose: Convert the contents of a DICOM file to JSON format
-*
-*/
+ *
+ *  Copyright (C) 2016-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Sebastian Grallert, Marco Eichelberg
+ *
+ *  Purpose: Convert the contents of a DICOM file to JSON format
+ *
+ */
 
 #include "dcmtk/config/osconfig.h"      /* make sure OS specific configuration is included first */
 
@@ -28,6 +28,9 @@
 #include "dcmtk/ofstd/ofstream.h"
 #include "dcmtk/ofstd/ofconapp.h"
 #include "dcmtk/ofstd/ofexit.h"
+#include "dcmtk/ofstd/ofstd.h"
+
+#include <cstdlib>
 
 #ifdef WITH_ZLIB
 #include <zlib.h>                       /* for zlibVersion() */
@@ -35,6 +38,9 @@
 #ifdef DCMTK_ENABLE_CHARSET_CONVERSION
 #include "dcmtk/ofstd/ofchrenc.h"       /* for OFCharacterEncoding */
 #endif
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
 
 #define OFFIS_CONSOLE_APPLICATION "dcm2json"
 #define OFFIS_CONSOLE_DESCRIPTION "Convert DICOM file and data set to JSON"
@@ -42,6 +48,8 @@
 #define EXITCODE_CANNOT_CONVERT_TO_UNICODE 80
 #define EXITCODE_CANNOT_WRITE_VALID_JSON   81
 
+#define DCM2JSON_WELL_KNOWN_UID "1.2.276.0.7230010.3.1.4.1787205428.3192777.1748004619.679033"
+
 static OFLogger dcm2jsonLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
 
 static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
@@ -49,18 +57,36 @@ OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
 
 // ********************************************
 
-/* Function to call all writeJson() functions in DCMTK */
-static OFCondition writeFile(STD_NAMESPACE ostream &out,
-    const char *ifname,
+/** Convert a DICOM file to JSON.
+ *  @param out output stream to write JSON to
+ *  @param dfile pointer to the DICOM object, must not be NULL
+ *  @param readMode mode used to read the file. Determines whether conversion
+ *    takes place at DcmFileFormat or DcmDataset level.
+ *  @param format OFTrue for pretty printing, OFFalse for compact code
+ *  @param printMetaInfo If true, the meta-header attributes are also converted
+ *     to JSON as a non-standard DCMTK extension
+ *  @param encode_extended enables an extension of the JSON syntax to permit
+ *     "-inf", "nan" and "inf" to be generated for infinity and not-a-number values
+ *  @param opt_ns_policy policy for converting IS/DS values to JSON
+ *  @param min_bulk_size minimum size for bulk data, negative number to disable bulk data
+ *  @param bulk_uri_prefix prefix string for bulk data URIs
+ *  @param bulk_dir directory to which bulk data should be written
+ *  @return EC_Normal if successful, and error code otherwise
+ */
+static OFCondition writeFile(
+    STD_NAMESPACE ostream &out,
     DcmFileFormat *dfile,
     const E_FileReadMode readMode,
     const OFBool format,
     const OFBool printMetaInfo,
     const OFBool encode_extended,
-    const DcmJsonFormat::NumStringPolicy opt_ns_policy)
+    const DcmJsonFormat::NumStringPolicy opt_ns_policy,
+    const OFCmdSignedInt min_bulk_size,
+    const char *bulk_uri_prefix,
+    const char *bulk_dir)
 {
     OFCondition result = EC_IllegalParameter;
-    if ((ifname != NULL) && (dfile != NULL))
+    if (dfile != NULL)
     {
         /* write JSON document content */
         DcmDataset *dset = dfile->getDataset();
@@ -69,6 +95,9 @@ static OFCondition writeFile(STD_NAMESPACE ostream &out,
             DcmJsonFormatPretty fmt(printMetaInfo);
             fmt.setJsonExtensionEnabled(encode_extended);
             fmt.setJsonNumStringPolicy(opt_ns_policy);
+            fmt.setMinBulkSize(OFstatic_cast(ssize_t, min_bulk_size));
+            fmt.setBulkURIPrefix(bulk_uri_prefix);
+            fmt.setBulkDir(bulk_dir);
             if (readMode == ERM_dataset)
                result = dset->writeJsonExt(out, fmt, OFTrue, OFTrue);
                else result = dfile->writeJson(out, fmt);
@@ -78,6 +107,9 @@ static OFCondition writeFile(STD_NAMESPACE ostream &out,
             DcmJsonFormatCompact fmt(printMetaInfo);
             fmt.setJsonExtensionEnabled(encode_extended);
             fmt.setJsonNumStringPolicy(opt_ns_policy);
+            fmt.setMinBulkSize(OFstatic_cast(ssize_t, min_bulk_size));
+            fmt.setBulkURIPrefix(bulk_uri_prefix);
+            fmt.setBulkDir(bulk_dir);
             if (readMode == ERM_dataset)
                result = dset->writeJsonExt(out, fmt, OFTrue, OFTrue);
                else result = dfile->writeJson(out, fmt);
@@ -86,6 +118,67 @@ static OFCondition writeFile(STD_NAMESPACE ostream &out,
     return result;
 }
 
+/** append the given file path to the output URL while URL-encoding
+ *  special characters. Note that the reserved characters '/' and
+ *  ':' are not encoding since they are routinely used in file: URLs.
+ *  @param path file path
+ *  @param output_url output URL
+ */
+static void appendURLEncodedPath(const char *path, OFString& output_url)
+{
+  if (path)
+  {
+    char c;
+    for (const char *p=path; *p != '\0'; ++p)
+    {
+      c = *p;
+      // URL encode all characters except a-z, A-Z, 0-9, and "-_./!~$:"
+      // The reserved characters "/" and ":" are not URL encoded because they routinely occur in file: URLs
+      if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '/' || c == '!' || c == '~' || c == '$' || c == ':') output_url.append(1, *p);
+      else if (c == '\\')
+      {
+          // convert backslashes to forward slashes
+          output_url.append("/");
+      }
+      else
+      {
+          char buf[5];
+          OFStandard::snprintf(buf, 5, "%%%02X", c);
+          output_url.append(buf);
+      }
+    }
+  }
+}
+
+/** determine the real path to the given working directory
+ *  and return it in the form of a file:// URI.
+ *  @param input_dir current working directory, NULL for current directory
+ *  @param output_dir file URI to real path (without symbolic links) returned in this parameter if successful
+ *  @return EC_Normal if successful, and error code otherwise
+ */
+static OFCondition getCurrentWorkingDir(const char *input_dir, OFString& output_dir)
+{
+    // if dir is empty, assume current directory
+    if (input_dir == NULL) input_dir = ".";
+
+#ifdef HAVE_WINDOWS_H
+    char *resolved_path = _fullpath(NULL, input_dir, 0);
+#else
+    char *resolved_path = realpath(input_dir, NULL);
+#endif
+    if (resolved_path == NULL)
+    {
+        OFLOG_ERROR(dcm2jsonLogger, OFFIS_CONSOLE_APPLICATION << ": Cannot create or determine bulk data directory");
+        return EC_DirectoryDoesNotExist;
+    }
+    output_dir = "file://localhost";
+    if (resolved_path[0] != '/') output_dir.append("/");
+    appendURLEncodedPath(resolved_path, output_dir);
+    output_dir.append("/");
+    free(resolved_path);
+    return EC_Normal;
+}
+
 #define SHORTCOL 3
 #define LONGCOL 20
 
@@ -100,6 +193,12 @@ int main(int argc, char *argv[])
     E_TransferSyntax opt_ixfer = EXS_Unknown;
     OFString optStr;
 
+    OFCmdSignedInt opt_min_bulk_size = -1;
+    const char *opt_bulk_uri_prefix = NULL;
+    const char *opt_bulk_dir = ".";
+    OFBool opt_bulk_subdir = OFFalse;
+    OFString bulkURIPrefix;
+
     OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, OFFIS_CONSOLE_DESCRIPTION, rcsid);
     OFCommandLine cmd;
     cmd.setOptionColumns(LONGCOL, SHORTCOL);
@@ -115,30 +214,37 @@ int main(int argc, char *argv[])
 
     cmd.addGroup("input options:");
       cmd.addSubGroup("input file format:");
-        cmd.addOption("--read-file",          "+f",  "read file format or data set (default)");
-        cmd.addOption("--read-file-only",     "+fo", "read file format only");
-        cmd.addOption("--read-dataset",       "-f",  "read data set without file meta information");
+        cmd.addOption("--read-file",          "+f",     "read file format or data set (default)");
+        cmd.addOption("--read-file-only",     "+fo",    "read file format only");
+        cmd.addOption("--read-dataset",       "-f",     "read data set without file meta information");
       cmd.addSubGroup("input transfer syntax:");
-        cmd.addOption("--read-xfer-auto",     "-t=", "use TS recognition (default)");
-        cmd.addOption("--read-xfer-detect",   "-td", "ignore TS specified in the file meta header");
-        cmd.addOption("--read-xfer-little",   "-te", "read with explicit VR little endian TS");
-        cmd.addOption("--read-xfer-big",      "-tb", "read with explicit VR big endian TS");
-        cmd.addOption("--read-xfer-implicit", "-ti", "read with implicit VR little endian TS");
+        cmd.addOption("--read-xfer-auto",     "-t=",    "use TS recognition (default)");
+        cmd.addOption("--read-xfer-detect",   "-td",    "ignore TS specified in the file meta header");
+        cmd.addOption("--read-xfer-little",   "-te",    "read with explicit VR little endian TS");
+        cmd.addOption("--read-xfer-big",      "-tb",    "read with explicit VR big endian TS");
+        cmd.addOption("--read-xfer-implicit", "-ti",    "read with implicit VR little endian TS");
 
     cmd.addGroup("processing options:");
       cmd.addSubGroup("encoding of infinity and not-a-number:");
-        cmd.addOption("--encode-strict",      "-es", "report error for 'inf' and 'nan' (default)");
-        cmd.addOption("--encode-extended",    "-ee", "permit 'inf' and 'nan' in JSON numbers");
+        cmd.addOption("--encode-strict",      "-es",    "report error for 'inf' and 'nan' (default)");
+        cmd.addOption("--encode-extended",    "-ee",    "permit 'inf' and 'nan' in JSON numbers");
       cmd.addSubGroup("encoding of IS and DS (integer/decimal string) elements:");
-        cmd.addOption("--is-ds-auto",         "-ia", "encode as number if valid, as string\notherwise (default)");
-        cmd.addOption("--is-ds-num",          "-in", "always encode as number, fail if invalid");
-        cmd.addOption("--is-ds-string",       "-is", "always encode as string");
+        cmd.addOption("--is-ds-auto",         "-ia",    "encode as number if valid, as string\notherwise (default)");
+        cmd.addOption("--is-ds-num",          "-in",    "always encode as number, fail if invalid");
+        cmd.addOption("--is-ds-string",       "-is",    "always encode as string");
+      cmd.addSubGroup("bulk data URI options:");
+        cmd.addOption("--bulk-disabled",      "-b",     "write everything as inline binary (default)");
+        cmd.addOption("--bulk-enabled",       "+b",     "write large attributes as bulk data");
+        cmd.addOption("--bulk-size",          "+bz", 1, "[s]ize: integer (default: 1)", "use bulk data for attributes >= s kBytes");
+        cmd.addOption("--bulk-uri-prefix",    "+bp", 1, "[u]ri prefix: string",  "use prefix u when generating bulk data URIs\n(default: file URI)");
+        cmd.addOption("--bulk-dir",           "+bd", 1, "[d]irectory: string",  "write bulk data files to d (default: '.')");
+        cmd.addOption("--bulk-subdir",        "+bs",    "create subdirectory for each SOP instance\n(default: no subdirectory)");
 
     cmd.addGroup("output options:");
       cmd.addSubGroup("output format:");
-        cmd.addOption("--formatted-code",     "+fc", "enable whitespace formatting (default)");
-        cmd.addOption("--compact-code",       "-fc", "print only required characters");
-        cmd.addOption("--write-meta",         "+m",  "write data set with meta information\n(warning: not conforming to the DICOM standard)");
+        cmd.addOption("--formatted-code",     "+fc",    "enable whitespace formatting (default)");
+        cmd.addOption("--compact-code",       "-fc",    "print only required characters");
+        cmd.addOption("--write-meta",         "+m",     "write data set with meta information\n(warning: not conforming to the DICOM standard)");
 
     /* evaluate command line */
     prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
@@ -215,6 +321,37 @@ int main(int argc, char *argv[])
             opt_ns_policy = DcmJsonFormat::NSP_always_string;
         cmd.endOptionBlock();
 
+        cmd.beginOptionBlock();
+        if (cmd.findOption("--bulk-disabled"))
+            opt_min_bulk_size = -1;
+        if (cmd.findOption("--bulk-enabled"))
+            opt_min_bulk_size = 1;
+        cmd.endOptionBlock();
+
+        if (cmd.findOption("--bulk-size"))
+        {
+            app.checkDependence("--bulk-size", "--bulk-enabled", opt_min_bulk_size >= 0);
+            app.checkValue(cmd.getValueAndCheckMin(opt_min_bulk_size, 0));
+        }
+
+        if (cmd.findOption("--bulk-uri-prefix"))
+        {
+            app.checkDependence("--bulk-uri-prefix", "--bulk-enabled", opt_min_bulk_size >= 0);
+            app.checkValue(cmd.getValue(opt_bulk_uri_prefix));
+        }
+
+        if (cmd.findOption("--bulk-dir"))
+        {
+            app.checkDependence("--bulk-dir", "--bulk-enabled", opt_min_bulk_size >= 0);
+            app.checkValue(cmd.getValue(opt_bulk_dir));
+        }
+
+        if (cmd.findOption("--bulk-subdir"))
+        {
+            app.checkDependence("--bulk-subdir", "--bulk-enabled", opt_min_bulk_size >= 0);
+            opt_bulk_subdir = OFTrue;
+        }
+
         /* format options */
         cmd.beginOptionBlock();
         if (cmd.findOption("--formatted-code"))
@@ -241,67 +378,89 @@ int main(int argc, char *argv[])
             << DCM_DICT_ENVIRONMENT_VARIABLE);
     }
 
+    OFCondition status;
+    if ((opt_min_bulk_size >= 0) && (opt_bulk_uri_prefix == NULL))
+    {
+       // try to create bulk directory, ignore failure
+       (void) OFStandard::createDirectory(opt_bulk_dir, "");
+
+        // determine default Bulk URI prefix
+        status = getCurrentWorkingDir(opt_bulk_dir, bulkURIPrefix);
+        if (status.bad())
+        {
+            return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+        }
+        opt_bulk_uri_prefix = bulkURIPrefix.c_str();
+    }
+
     int result = 0;
     /* first parameter is treated as the input filename */
     const char *ifname = NULL;
     cmd.getParam(1, ifname);
+
     /* check input file */
     if ((ifname != NULL) && (strlen(ifname) > 0))
     {
         /* read DICOM file or data set */
         DcmFileFormat dfile;
-        OFCondition status = dfile.loadFile(ifname, opt_ixfer, EGL_noChange, DCM_MaxReadLength, opt_readMode);
+        status = dfile.loadFile(ifname, opt_ixfer, EGL_noChange, DCM_MaxReadLength, opt_readMode);
         if (status.good())
         {
             DcmDataset *dset = dfile.getDataset();
-            OFString csetString;
-            if (dset->findAndGetOFStringArray(DCM_SpecificCharacterSet, csetString).good())
+            /* check for SpecificCharacterSet on any data set level */
+            if (dset->tagExistsWithValue(DCM_SpecificCharacterSet, OFTrue /*searchIntoSub*/))
             {
-                if (csetString.compare("ISO_IR 6") == 0)
+                /* convert entire DICOM file or data set to UTF-8 encoding */
+                status = dfile.convertToUTF8();
+                if (status.bad())
                 {
-                    /* SpecificCharacterSet indicates ASCII without extended characters.
-                     * If this is true, no conversion is necessary. Check for extended characters.
-                     */
-                    if (dset->containsExtendedCharacters(OFFalse /*checkAllStrings*/))
-                    {
-                        OFLOG_FATAL(dcm2jsonLogger, "dataset contains extended characters but SpecificCharacterSet (0008,0005) is 'ISO_IR 6'");
-                        result = EXITCODE_CANNOT_CONVERT_TO_UNICODE;
-                    }
-                }
-                else if (csetString.compare("ISO_IR 192") == 0)
-                {
-                    /* DICOM dataset is already in UTF-8, no conversion necessary */
-                }
-                else
-                {
-                    /* we have a character set other than ASCII or UTF-8. Perform conversion. */
-#ifdef DCMTK_ENABLE_CHARSET_CONVERSION
-                    /* convert all DICOM strings to UTF-8 */
-                    OFLOG_INFO(dcm2jsonLogger, "converting all element values that are affected by SpecificCharacterSet (0008,0005) to UTF-8");
-                    status = dset->convertToUTF8();
-                    if (status.bad())
-                    {
-                        OFLOG_FATAL(dcm2jsonLogger, status.text() << ": converting file to UTF-8: " << ifname);
-                        result = EXITCODE_CANNOT_CONVERT_TO_UNICODE;
-                    }
-#else
-                    OFLOG_FATAL(dcm2jsonLogger, "character set conversion not available");
+                    OFLOG_FATAL(dcm2jsonLogger, status.text() << ": converting file to UTF-8: " << ifname);
                     result = EXITCODE_CANNOT_CONVERT_TO_UNICODE;
-#endif
                 }
             }
             else
             {
-              /* SpecificCharacterSet not present */
-              if (dset->containsExtendedCharacters(OFFalse /*checkAllStrings*/))
-              {
-                  OFLOG_FATAL(dcm2jsonLogger, "dataset contains extended characters but no SpecificCharacterSet (0008,0005)");
-                  result = EXITCODE_CANNOT_CONVERT_TO_UNICODE;
-              }
+                if (dset->containsExtendedCharacters(OFFalse /*checkAllStrings*/))
+                {
+                    OFLOG_ERROR(dcm2jsonLogger, OFFIS_CONSOLE_APPLICATION << ": SpecificCharacterSet (0008,0005) element "
+                        << "absent (at all levels of the data set) but extended characters used in file: " << ifname);
+                    result = EXITCODE_CANNOT_CONVERT_TO_UNICODE;
+                }
             }
 
             if (result == 0)
             {
+
+                // look for the SOP instance UID, first in the dataset, then in the metaheader
+                OFString subDir;
+                OFString bulkDir = opt_bulk_dir;
+                OFString bulkURIPrefixWithSubdir;
+                if (opt_bulk_uri_prefix) bulkURIPrefixWithSubdir = opt_bulk_uri_prefix;
+                if ((opt_min_bulk_size >= 0) && opt_bulk_subdir)
+                {
+                    if (dfile.getDataset()->findAndGetOFString(DCM_SOPInstanceUID, subDir).bad()
+                       && dfile.getMetaInfo()->findAndGetOFString(DCM_SOPInstanceUID, subDir).bad())
+                    {
+                        // no SOP instance UID found. Use hard coded default UID instead.
+                        subDir = DCM2JSON_WELL_KNOWN_UID;
+                    }
+
+                    bulkURIPrefixWithSubdir.append(subDir);
+                    bulkURIPrefixWithSubdir.append("/");
+
+                    bulkDir.append(1, PATH_SEPARATOR);
+                    bulkDir.append(subDir);
+                    if (! OFStandard::dirExists(bulkDir))
+                    {
+                        status = OFStandard::createDirectory(bulkDir, opt_bulk_dir);
+                        if (status.bad())
+                        {
+                            OFLOG_FATAL(dcm2jsonLogger, status.text() << ": " << ifname);
+                            return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+                        }
+                    }
+                }
+
                 /* if second parameter is present, it is treated as the output filename ("stdout" otherwise) */
                 if (cmd.getParamCount() == 2)
                 {
@@ -311,7 +470,8 @@ int main(int argc, char *argv[])
                     if (stream.good())
                     {
                         /* write content in JSON format to file */
-                        status = writeFile(stream, ifname, &dfile, opt_readMode, opt_format, opt_addMetaInformation, opt_encode_extended, opt_ns_policy);
+                        status = writeFile(stream, &dfile, opt_readMode, opt_format, opt_addMetaInformation,
+                            opt_encode_extended, opt_ns_policy, opt_min_bulk_size, bulkURIPrefixWithSubdir.c_str(), bulkDir.c_str());
                         if (status.bad())
                         {
                             OFLOG_FATAL(dcm2jsonLogger, status.text() << ": " << ifname);
@@ -324,7 +484,8 @@ int main(int argc, char *argv[])
                 else
                 {
                     /* write content in JSON format to standard output */
-                    status = writeFile(COUT, ifname, &dfile, opt_readMode, opt_format, opt_addMetaInformation, opt_encode_extended, opt_ns_policy);
+                    status = writeFile(COUT, &dfile, opt_readMode, opt_format, opt_addMetaInformation,
+                        opt_encode_extended, opt_ns_policy, opt_min_bulk_size, bulkURIPrefixWithSubdir.c_str(), bulkDir.c_str());
                     if (status.bad())
                     {
                         OFLOG_FATAL(dcm2jsonLogger, status.text() << ": " << ifname);
index f00de6e3bf1db132690806f5c863b40c647bb70a..08a1ed044e1637f0ba49b9cd9f49e02999c76fb2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2024, OFFIS e.V.
+ *  Copyright (C) 2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *  Module:  dcmdata
  *
- *  Author Marco Eichelberg
+ *  Authors: Marco Eichelberg
  *
- *  Purpose: Extract PDF file from DICOM encapsulated PDF storage object
+ *  Purpose: Proxy stub that calls dcmdecap
  *
  */
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofstub.h"
 
-BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>       /* for O_RDONLY */
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>   /* required for sys/stat.h */
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>    /* for stat, fstat */
-#endif
-END_EXTERN_C
-
-#include "dcmtk/dcmdata/dctk.h"
-#include "dcmtk/dcmdata/cmdlnarg.h"
-#include "dcmtk/ofstd/ofconapp.h"
-#include "dcmtk/dcmdata/dcuid.h"       /* for dcmtk version name */
-#include "dcmtk/ofstd/ofstd.h"
-#include "dcmtk/dcmdata/dcistrmz.h"    /* for dcmZlibExpectRFC1950Encoding */
-
-#ifdef WITH_ZLIB
-#include <zlib.h>        /* for zlibVersion() */
-#endif
-
-#define OFFIS_CONSOLE_APPLICATION "dcm2pdf"
-
-static OFLogger dcm2pdfLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
-
-static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
-    OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
-
-#define FILENAME_PLACEHOLDER "#f"
-
-static OFString replaceChars(const OFString &srcstr, const OFString &pattern, const OFString &substitute)
-/*
- * This function replaces all occurrences of pattern in srcstr with substitute and returns
- * the result as a new OFString variable. Note that srcstr itself will not be changed.
- *
- * Parameters:
- *   srcstr     - [in] The source string.
- *   pattern    - [in] The pattern string which shall be substituted.
- *   substitute - [in] The substitute for pattern in srcstr.
- */
-{
-    OFString result = srcstr;
-    size_t pos = 0;
-
-    while (pos != OFString_npos)
-    {
-        pos = result.find(pattern, pos);
-
-        if (pos != OFString_npos)
-        {
-            result.replace(pos, pattern.size(), substitute);
-            pos += substitute.size();
-        }
-    }
-
-    return result;
-}
-
-
-#define SHORTCOL 3
-#define LONGCOL 20
-
-int main(int argc, char *argv[])
+int main(int argc, char** argv)
 {
-    const char *opt_ifname = NULL;
-    const char *opt_ofname = NULL;
-    const char    *opt_execString = NULL;
-    E_FileReadMode opt_readMode = ERM_autoDetect;
-    E_TransferSyntax opt_ixfer = EXS_Unknown;
-
-    OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Extract PDF file from DICOM encapsulated PDF", rcsid);
-    OFCommandLine cmd;
-    cmd.setOptionColumns(LONGCOL, SHORTCOL);
-    cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
-
-    cmd.addParam("dcmfile-in",  "DICOM input filename (\"-\" for stdin)");
-    cmd.addParam("pdffile-out", "PDF output filename");
-
-    cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
-        cmd.addOption("--help",                 "-h",     "print this help text and exit", OFCommandLine::AF_Exclusive);
-        cmd.addOption("--version",                        "print version information and exit", OFCommandLine::AF_Exclusive);
-        OFLog::addOptions(cmd);
-
-    cmd.addGroup("input options:");
-        cmd.addSubGroup("input file format:");
-            cmd.addOption("--read-file",          "+f",     "read file format or data set (default)");
-            cmd.addOption("--read-file-only",     "+fo",    "read file format only");
-            cmd.addOption("--read-dataset",       "-f",     "read data set without file meta information");
-        cmd.addSubGroup("input transfer syntax:");
-            cmd.addOption("--read-xfer-auto",     "-t=",    "use TS recognition (default)");
-            cmd.addOption("--read-xfer-detect",   "-td",    "ignore TS specified in the file meta header");
-            cmd.addOption("--read-xfer-little",   "-te",    "read with explicit VR little endian TS");
-            cmd.addOption("--read-xfer-big",      "-tb",    "read with explicit VR big endian TS");
-            cmd.addOption("--read-xfer-implicit", "-ti",    "read with implicit VR little endian TS");
-        cmd.addSubGroup("parsing of odd-length attributes:");
-            cmd.addOption("--accept-odd-length",  "+ao",    "accept odd length attributes (default)");
-            cmd.addOption("--assume-even-length", "+ae",    "assume real length is one byte larger");
-        cmd.addSubGroup("handling of undefined length UN elements:");
-            cmd.addOption("--enable-cp246",       "+ui",    "read undefined len UN as implicit VR (default)");
-            cmd.addOption("--disable-cp246",      "-ui",    "read undefined len UN as explicit VR");
-        cmd.addSubGroup("handling of defined length UN elements:");
-            cmd.addOption("--retain-un",          "-uc",    "retain elements as UN (default)");
-            cmd.addOption("--convert-un",         "+uc",    "convert to real VR if known");
-        cmd.addSubGroup("automatic data correction:");
-            cmd.addOption("--enable-correction",  "+dc",    "enable automatic data correction (default)");
-            cmd.addOption("--disable-correction", "-dc",    "disable automatic data correction");
-#ifdef WITH_ZLIB
-        cmd.addSubGroup("bitstream format of deflated input:");
-            cmd.addOption("--bitstream-deflated", "+bd",    "expect deflated bitstream (default)");
-            cmd.addOption("--bitstream-zlib",     "+bz",    "expect deflated zlib bitstream");
-#endif
-
-    cmd.addGroup("processing options:");
-    cmd.addSubGroup("execution options:");
-        cmd.addOption("--exec",                "-x",  1, "[c]ommand: string",
-                                                         "execute command c after PDF extraction");
-    /* evaluate command line */
-    prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
-    if (app.parseCommandLine(cmd, argc, argv))
-    {
-        /* check exclusive options first */
-        if (cmd.hasExclusiveOption())
-        {
-            if (cmd.findOption("--version"))
-            {
-                app.printHeader(OFTrue /*print host identifier*/);
-                COUT << OFendl << "External libraries used:";
-#ifdef WITH_ZLIB
-                COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
-#else
-                COUT << " none" << OFendl;
-#endif
-                return EXITCODE_NO_ERROR;
-            }
-        }
-
-        /* command line parameters and options */
-        cmd.getParam(1, opt_ifname);
-        cmd.getParam(2, opt_ofname);
-
-        OFLog::configureFromCommandLine(cmd, app);
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--read-file")) opt_readMode = ERM_autoDetect;
-        if (cmd.findOption("--read-file-only")) opt_readMode = ERM_fileOnly;
-        if (cmd.findOption("--read-dataset")) opt_readMode = ERM_dataset;
-        cmd.endOptionBlock();
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--read-xfer-auto"))
-            opt_ixfer = EXS_Unknown;
-        if (cmd.findOption("--read-xfer-detect"))
-            dcmAutoDetectDatasetXfer.set(OFTrue);
-        if (cmd.findOption("--read-xfer-little"))
-        {
-            app.checkDependence("--read-xfer-little", "--read-dataset", opt_readMode == ERM_dataset);
-            opt_ixfer = EXS_LittleEndianExplicit;
-        }
-        if (cmd.findOption("--read-xfer-big"))
-        {
-            app.checkDependence("--read-xfer-big", "--read-dataset", opt_readMode == ERM_dataset);
-            opt_ixfer = EXS_BigEndianExplicit;
-        }
-        if (cmd.findOption("--read-xfer-implicit"))
-        {
-            app.checkDependence("--read-xfer-implicit", "--read-dataset", opt_readMode == ERM_dataset);
-            opt_ixfer = EXS_LittleEndianImplicit;
-        }
-        cmd.endOptionBlock();
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--accept-odd-length"))
-        {
-            dcmAcceptOddAttributeLength.set(OFTrue);
-        }
-        if (cmd.findOption("--assume-even-length"))
-        {
-            dcmAcceptOddAttributeLength.set(OFFalse);
-        }
-        cmd.endOptionBlock();
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--enable-cp246"))
-        {
-            dcmEnableCP246Support.set(OFTrue);
-        }
-        if (cmd.findOption("--disable-cp246"))
-        {
-            dcmEnableCP246Support.set(OFFalse);
-        }
-        cmd.endOptionBlock();
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--retain-un"))
-        {
-            dcmEnableUnknownVRConversion.set(OFFalse);
-        }
-        if (cmd.findOption("--convert-un"))
-        {
-            dcmEnableUnknownVRConversion.set(OFTrue);
-        }
-        cmd.endOptionBlock();
-
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--enable-correction"))
-        {
-            dcmEnableAutomaticInputDataCorrection.set(OFTrue);
-        }
-        if (cmd.findOption("--disable-correction"))
-        {
-            dcmEnableAutomaticInputDataCorrection.set(OFFalse);
-        }
-        cmd.endOptionBlock();
-
-#ifdef WITH_ZLIB
-        cmd.beginOptionBlock();
-        if (cmd.findOption("--bitstream-deflated"))
-        {
-            dcmZlibExpectRFC1950Encoding.set(OFFalse);
-        }
-        if (cmd.findOption("--bitstream-zlib"))
-        {
-            dcmZlibExpectRFC1950Encoding.set(OFTrue);
-        }
-        cmd.endOptionBlock();
-#endif
-
-        if (cmd.findOption("--exec"))
-            app.checkValue(cmd.getValue(opt_execString));
-    }
-
-    /* print resource identifier */
-    OFLOG_DEBUG(dcm2pdfLogger, rcsid << OFendl);
-
-    /* make sure data dictionary is loaded */
-    if (!dcmDataDict.isDictionaryLoaded())
-    {
-        OFLOG_WARN(dcm2pdfLogger, "no data dictionary loaded, check environment variable: "
-            << DCM_DICT_ENVIRONMENT_VARIABLE);
-    }
-
-    // open inputfile
-    if ((opt_ifname == NULL) || (strlen(opt_ifname) == 0))
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "invalid filename: <empty string>");
-        return EXITCODE_NO_INPUT_FILES;
-    }
-
-    DcmFileFormat fileformat;
-    DcmDataset * dataset = fileformat.getDataset();
-
-    OFLOG_INFO(dcm2pdfLogger, "open input file " << opt_ifname);
-
-    OFCondition error = fileformat.loadFile(opt_ifname, opt_ixfer, EGL_noChange, DCM_MaxReadLength, opt_readMode);
-
-    if (error.bad())
-    {
-        OFLOG_FATAL(dcm2pdfLogger, error.text() << ": reading file: " << opt_ifname);
-        return EXITCODE_CANNOT_READ_INPUT_FILE;
-    }
-
-    OFString sopClass;
-    error = dataset->findAndGetOFString(DCM_SOPClassUID, sopClass);
-    if (error.bad() || sopClass != UID_EncapsulatedPDFStorage)
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "not an Encapsulated PDF object: " << opt_ifname);
-        return EXITCODE_INVALID_INPUT_FILE;
-    }
-
-    DcmElement *delem = NULL;
-    error = dataset->findAndGetElement(DCM_EncapsulatedDocument, delem);
-    if (error.bad() || delem == NULL)
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "Encapsulated Document missing.");
-        return EXITCODE_INVALID_INPUT_FILE;
-    }
-
-    Uint32 len = delem->getLength();
-    Uint8 *pdfDocument = NULL;
-    error = delem->getUint8Array(pdfDocument);
-    if (error.bad() || pdfDocument == NULL || len == 0)
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "Encapsulated Document empty or wrong VR.");
-        return EXITCODE_INVALID_INPUT_FILE;
-    }
-
-    /* strip pad byte at end of file, if there is one. The PDF format expects
-     * files to end with %%EOF followed by CR/LF (although in some cases the
-     * CR/LF may be missing or you might only find CR or LF).
-     * If the last character of the file is not a CR or LF, and not the
-     * letter 'F', we assume it is either trailing garbage or a pad byte, and remove it.
-     */
-    if (pdfDocument[len-1] != 10 && pdfDocument[len-1] != 13 && pdfDocument[len-1] != 'F')
-    {
-        --len;
-    }
-
-    OFLOG_INFO(dcm2pdfLogger, "writing PDF file to " << opt_ofname);
-    FILE *pdffile = fopen(opt_ofname, "wb");
-    if (pdffile == NULL)
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "unable to create file " << opt_ofname);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    if (len != fwrite(pdfDocument, 1, len, pdffile))
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "write error in file " << opt_ofname);
-        fclose(pdffile);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    if(fclose(pdffile))
-    {
-        OFLOG_FATAL(dcm2pdfLogger, "write error in file " << opt_ofname);
-        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-    }
-
-    OFLOG_INFO(dcm2pdfLogger, "conversion successful");
-
-    if (opt_execString)
-    {
-        OFString cmdStr = opt_execString;
-        cmdStr = replaceChars(cmdStr, OFString(FILENAME_PLACEHOLDER), opt_ofname);
-
-        // Execute command and return result
-        return system(cmdStr.c_str());
-    }
-
-    return EXITCODE_NO_ERROR;
+    // call stub. Will not return on Posix systems.
+    return OFstub_main(argc, argv, "dcm2pdf", "dcmdecap");
 }
index 611812848558351df40f01aaa54831759b73e051..a2b41a3d16d64a08b13bc279109169aacb6268c5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2022, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -105,13 +105,32 @@ static OFCondition checkCharacterSet(const char *ifname,
             /* SpecificCharacterSet is not present in the dataset */
             if (dset->containsExtendedCharacters(checkAllStrings))
             {
+                OFString sopClass;
+                /* check whether this file is a DICOMDIR */
+                const OFBool isDICOMDIR = dfile.getMetaInfo()->findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClass).good() &&
+                    (sopClass == UID_MediaStorageDirectoryStorage);
                 if (defaultCharset == NULL)
                 {
-                    /* the dataset contains non-ASCII characters that really should not be there */
-                    OFLOG_ERROR(dcm2xmlLogger, OFFIS_CONSOLE_APPLICATION << ": SpecificCharacterSet (0008,0005) "
-                        << "element absent (on the main data set level) but extended characters used in file: " << ifname);
-                    OFLOG_DEBUG(dcm2xmlLogger, "use option --charset-assume to manually specify an appropriate character set");
-                    result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotSelectCharacterSet, OF_error, "Missing Specific Character Set");;
+                    if (isDICOMDIR)
+                    {
+                        /* check for SpecificCharacterSet on any data set level */
+                        if (dset->tagExistsWithValue(DCM_SpecificCharacterSet, OFTrue /*searchIntoSub*/))
+                        {
+                            /* for now, we assume that everything is ok */
+                            result = EC_Normal;
+                        } else {
+                            OFLOG_ERROR(dcm2xmlLogger, OFFIS_CONSOLE_APPLICATION << ": SpecificCharacterSet (0008,0005) element "
+                                << "absent (at all levels of the data set) but extended characters used in file: " << ifname);
+                            OFLOG_DEBUG(dcm2xmlLogger, "try using option --charset-assume to manually specify an appropriate character set");
+                            result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotSelectCharacterSet, OF_error, "Missing Specific Character Set");
+                        }
+                    } else {
+                        /* the dataset contains non-ASCII characters that really should not be there */
+                        OFLOG_ERROR(dcm2xmlLogger, OFFIS_CONSOLE_APPLICATION << ": SpecificCharacterSet (0008,0005) element "
+                            << "absent (at the main level of the data set) but extended characters used in file: " << ifname);
+                        OFLOG_DEBUG(dcm2xmlLogger, "use option --charset-assume to manually specify an appropriate character set");
+                        result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotSelectCharacterSet, OF_error, "Missing Specific Character Set");
+                    }
                 } else {
                     result = EC_Normal;
                     csetString = defaultCharset;
@@ -164,17 +183,11 @@ static OFCondition checkCharacterSet(const char *ifname,
                             << defaultCharset << "' specified with option --charset-assume not supported");
                         result = makeOFCondition(OFM_dcmdata, EC_CODE_CannotSelectCharacterSet, OF_error, "Cannot select character set");
                     }
-                    if (result.good())
+                    if (result.good() && !isDICOMDIR)
                     {
-                        OFString sopClass;
-                        /* check whether this file is a DICOMDIR */
-                        if (dfile.getMetaInfo()->findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClass).bad() ||
-                            (sopClass != UID_MediaStorageDirectoryStorage))
-                        {
-                            OFLOG_INFO(dcm2xmlLogger, "inserting SpecificCharacterSet (0008,0005) element with value '" << csetString << "'");
-                            /* insert the SpecificCharacterSet (0008,0005) element with new value */
-                            result = dset->putAndInsertOFStringArray(DCM_SpecificCharacterSet, csetString);
-                        }
+                        OFLOG_INFO(dcm2xmlLogger, "inserting SpecificCharacterSet (0008,0005) element with value '" << csetString << "'");
+                        /* insert the SpecificCharacterSet (0008,0005) element with new value */
+                        result = dset->putAndInsertOFStringArray(DCM_SpecificCharacterSet, csetString);
                     }
                 }
             } else {
@@ -204,13 +217,12 @@ static OFCondition convertCharacterSet(const char *ifname,
     OFCondition result = EC_IllegalParameter;
     if (ifname != NULL)
     {
-        DcmDataset *dset = dfile.getDataset();
         /* convert all DICOM strings to UTF-8 (if requested) */
         if (convertToUTF8)
         {
             OFLOG_INFO(dcm2xmlLogger, "converting all element values that are affected by SpecificCharacterSet (0008,0005) to UTF-8");
             /* expect that SpecificCharacterSet contains the correct value (defined term) */
-            result = dset->convertToUTF8();
+            result = dfile.convertToUTF8();
             if (result.good())
             {
                 /* if conversion was successful, set XML character encoding accordingly */
@@ -224,7 +236,7 @@ static OFCondition convertCharacterSet(const char *ifname,
                 (sopClass == UID_MediaStorageDirectoryStorage))
             {
                 /* ... with one or more SpecificCharacterSet elements */
-                if (dset->tagExistsWithValue(DCM_SpecificCharacterSet, OFTrue /*searchIntoSub*/))
+                if (dfile.getDataset()->tagExistsWithValue(DCM_SpecificCharacterSet, OFTrue /*searchIntoSub*/))
                 {
                     OFLOG_WARN(dcm2xmlLogger, OFFIS_CONSOLE_APPLICATION << ": this is a DICOMDIR file, which can contain more than one "
                         << "SpecificCharacterSet (0008,0005) element ... using option --convert-to-utf8 is strongly recommended");
diff --git a/dcmdata/apps/dcmdecap.cc b/dcmdata/apps/dcmdecap.cc
new file mode 100644 (file)
index 0000000..faae892
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ *
+ *  Copyright (C) 2007-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Marco Eichelberg, Tingyan Xu
+ *
+ *  Purpose: Extract encapsulated file from DICOM encapsulated storage object
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/dcmdata/dcuid.h"       /* for dcmtk version name */
+#include "dcmtk/dcmdata/dcistrmz.h"    /* for dcmZlibExpectRFC1950Encoding */
+#include "dcmtk/dcmdata/dcdocdec.h"    /* for class DcmDocumentDecapsulator */
+#include "dcmtk/dcmdata/dcdict.h"      /* for data dictionary */
+
+#ifdef WITH_ZLIB
+#include <zlib.h>        /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "dcmdecap"
+
+static OFLogger dcmdecapLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v" OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+#define SHORTCOL 3
+#define LONGCOL 20
+#define EXITCODE_EXEC_FAILED                 91
+
+
+static void addInputOptions(OFCommandLine& cmd)
+{
+    cmd.addGroup("input options:");
+    cmd.addSubGroup("input file format:");
+        cmd.addOption("--read-file",            "+f", "read file format or data set (default)");
+        cmd.addOption("--read-file-only",       "+fo", "read file format only");
+        cmd.addOption("--read-dataset",         "-f", "read data set without file meta information");
+
+    cmd.addSubGroup("input transfer syntax:");
+        cmd.addOption("--read-xfer-auto",       "-t=", "use TS recognition (default)");
+        cmd.addOption("--read-xfer-detect",     "-td", "ignore TS specified in the file meta header");
+        cmd.addOption("--read-xfer-little",     "-te", "read with explicit VR little endian TS");
+        cmd.addOption("--read-xfer-big",        "-tb", "read with explicit VR big endian TS");
+        cmd.addOption("--read-xfer-implicit",   "-ti", "read with implicit VR little endian TS");
+
+    cmd.addSubGroup("parsing of odd-length attributes:");
+        cmd.addOption("--accept-odd-length",    "+ao", "accept odd length attributes (default)");
+        cmd.addOption("--assume-even-length",   "+ae", "assume real length is one byte larger");
+
+    cmd.addSubGroup("handling of undefined length UN elements:");
+        cmd.addOption("--enable-cp246",         "+ui", "read undefined len UN as implicit VR (default)");
+        cmd.addOption("--disable-cp246",        "-ui", "read undefined len UN as explicit VR");
+
+    cmd.addSubGroup("handling of defined length UN elements:");
+        cmd.addOption("--retain-un",            "-uc", "retain elements as UN (default)");
+        cmd.addOption("--convert-un",           "+uc", "convert to real VR if known");
+
+    cmd.addSubGroup("automatic data correction:");
+        cmd.addOption("--enable-correction",    "+dc", "enable automatic data correction (default)");
+        cmd.addOption("--disable-correction",   "-dc", "disable automatic data correction");
+
+#ifdef WITH_ZLIB
+    cmd.addSubGroup("bitstream format of deflated input:");
+        cmd.addOption("--bitstream-deflated",   "+bd", "expect deflated bitstream (default)");
+        cmd.addOption("--bitstream-zlib",       "+bz", "expect deflated zlib bitstream");
+#endif
+}
+
+static void parseInputOptions(OFConsoleApplication& app, OFCommandLine& cmd, DcmDocumentDecapsulator& docdec)
+{
+    E_FileReadMode opt_readMode = ERM_autoDetect;
+    E_TransferSyntax opt_ixfer = EXS_Unknown;
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--read-file"))
+    {
+        opt_readMode = ERM_autoDetect;
+        docdec.setReadMode(opt_readMode);
+    }
+    if (cmd.findOption("--read-file-only"))
+    {
+        opt_readMode = ERM_fileOnly;
+        docdec.setReadMode(opt_readMode);
+    }
+    if (cmd.findOption("--read-dataset"))
+    {
+        opt_readMode = ERM_dataset;
+        docdec.setReadMode(opt_readMode);
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--read-xfer-auto"))
+    {
+        opt_ixfer = EXS_Unknown;
+        docdec.setInputXferSyntax(opt_ixfer);
+    }
+    if (cmd.findOption("--read-xfer-detect"))
+    {
+        dcmAutoDetectDatasetXfer.set(OFTrue);
+    }
+    if (cmd.findOption("--read-xfer-little"))
+    {
+        opt_ixfer = EXS_LittleEndianExplicit;
+        app.checkDependence("--read-xfer-little", "--read-dataset", opt_readMode == ERM_dataset);
+        docdec.setInputXferSyntax(opt_ixfer);
+    }
+    if (cmd.findOption("--read-xfer-big"))
+    {
+        opt_ixfer = EXS_BigEndianExplicit;
+        app.checkDependence("--read-xfer-big", "--read-dataset", opt_readMode == ERM_dataset);
+        docdec.setInputXferSyntax(opt_ixfer);
+    }
+    if (cmd.findOption("--read-xfer-implicit"))
+    {
+        opt_ixfer = EXS_LittleEndianImplicit;
+        app.checkDependence("--read-xfer-implicit", "--read-dataset", opt_readMode == ERM_dataset);
+        docdec.setInputXferSyntax(opt_ixfer);
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--accept-odd-length"))
+    {
+        dcmAcceptOddAttributeLength.set(OFTrue);
+    }
+    if (cmd.findOption("--assume-even-length"))
+    {
+        dcmAcceptOddAttributeLength.set(OFFalse);
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--enable-cp246"))
+    {
+        dcmEnableCP246Support.set(OFTrue);
+    }
+    if (cmd.findOption("--disable-cp246"))
+    {
+        dcmEnableCP246Support.set(OFFalse);
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--retain-un"))
+    {
+        dcmEnableUnknownVRConversion.set(OFFalse);
+    }
+    if (cmd.findOption("--convert-un"))
+    {
+        dcmEnableUnknownVRConversion.set(OFTrue);
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--enable-correction"))
+    {
+        dcmEnableAutomaticInputDataCorrection.set(OFTrue);
+    }
+    if (cmd.findOption("--disable-correction"))
+    {
+        dcmEnableAutomaticInputDataCorrection.set(OFFalse);
+    }
+    cmd.endOptionBlock();
+
+#ifdef WITH_ZLIB
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--bitstream-deflated"))
+    {
+        dcmZlibExpectRFC1950Encoding.set(OFFalse);
+    }
+    if (cmd.findOption("--bitstream-zlib"))
+    {
+        dcmZlibExpectRFC1950Encoding.set(OFTrue);
+    }
+    cmd.endOptionBlock();
+#endif
+}
+
+static void addProcessingOptions(OFCommandLine& cmd)
+{
+    cmd.addGroup("processing options:");
+    cmd.addSubGroup("execution options:");
+        cmd.addOption("--exec",                 "-x",  1, "[c]ommand: string",
+                                                          "execute command c after document extraction");
+}
+
+static void parseProcessingOptions(OFConsoleApplication& app, OFCommandLine& cmd, DcmDocumentDecapsulator& docdec)
+{
+    const char *c;
+    if (cmd.findOption("--exec"))
+    {
+        app.checkValue(cmd.getValue(c));
+        docdec.setExecString(c);
+    }
+}
+
+static void addCommandLineOptions(OFCommandLine& cmd)
+{
+    cmd.setOptionColumns(LONGCOL, SHORTCOL);
+    cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+    cmd.addParam("dcmfile-in",  "DICOM input filename (\"-\" for stdin)");
+    cmd.addParam("encfile-out", "Encapsulated document output filename\n(\"-\" for stdout)");
+    cmd.addGeneralOptions(LONGCOL, SHORTCOL);
+
+    OFLog::addOptions(cmd);
+
+    addInputOptions(cmd);
+    addProcessingOptions(cmd);
+}
+
+static void parseCommandLineOptions(OFConsoleApplication& app, OFCommandLine& cmd, DcmDocumentDecapsulator& docdec)
+{
+    const char *c;
+    cmd.getParam(1, c);
+    docdec.setInputFile(c);
+    cmd.getParam(2, c);
+    docdec.setOutputFile(c);
+    OFLog::configureFromCommandLine(cmd, app);
+    parseInputOptions(app, cmd, docdec);
+    parseProcessingOptions(app, cmd, docdec);
+}
+
+
+int main(int argc, char* argv[])
+{
+    DcmDocumentDecapsulator docdec;
+    OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Extract file from DICOM encapsulated storage", rcsid);
+    OFCommandLine cmd;
+    addCommandLineOptions(cmd);
+
+    // evaluate command line
+    prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+    if (app.parseCommandLine(cmd, argc, argv))
+    {
+        // check exclusive options first
+        if (cmd.hasExclusiveOption())
+        {
+            if (cmd.findOption("--version"))
+            {
+                app.printHeader(OFTrue /*print host identifier*/);
+                COUT << OFendl << "External libraries used:";
+#ifdef WITH_ZLIB
+                COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
+#else
+                COUT << " none" << OFendl;
+#endif
+                return EXITCODE_NO_ERROR;
+            }
+        }
+
+        // parse command line parameters and options
+        parseCommandLineOptions(app, cmd, docdec);
+    }
+
+    // print resource identifier
+    OFLOG_DEBUG(dcmdecapLogger, rcsid << OFendl);
+
+    // make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFLOG_WARN(dcmdecapLogger, "no data dictionary loaded, check environment variable: "
+            << DCM_DICT_ENVIRONMENT_VARIABLE);
+    }
+
+    // read the DICOM file
+    OFCondition cond = docdec.loadDICOMFile();
+    if (cond == EC_InvalidFilename) return EXITCODE_NO_INPUT_FILES;
+    else if (cond.bad()) return EXITCODE_CANNOT_READ_INPUT_FILE;
+
+    // extract the encapsulated document and write to file
+    cond = docdec.writeEncapsulatedContentToFile();
+    if (cond == EC_MissingAttribute) return EXITCODE_INVALID_INPUT_FILE;
+    else if (cond.bad()) return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+
+    // execute the command line (if defined)
+    cond = docdec.executeCommand();
+    if (cond.bad()) return EXITCODE_EXEC_FAILED;
+
+    // all done
+    return EXITCODE_NO_ERROR;
+}
diff --git a/dcmdata/apps/dcmencap.cc b/dcmdata/apps/dcmencap.cc
new file mode 100644 (file)
index 0000000..abc9768
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *
+ *  Copyright (C) 2018-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Pedro Arizpe, Marco Eichelberg
+ *
+ *  Purpose: Encapsulate document into DICOM format
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first*/
+#include "dcmtk/dcmdata/dcencdoc.h"
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/dcmdata/dcuid.h"
+#include "dcmtk/dcmdata/dcdict.h"
+#include "dcmtk/ofstd/ofconapp.h"
+
+
+#ifdef WITH_ZLIB
+#include <zlib.h>        /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "dcmencap"
+
+static OFLogger dcmencapLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
+
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
+OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+int main(int argc, char *argv[])
+{
+    OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Encapsulate document into DICOM format", rcsid);
+    OFCommandLine cmd;
+    OFCondition result = EC_Normal;
+    dcmEnableGenerationOfNewVRs();
+
+    // process command line options
+    DcmEncapsulatedDocument encapsulator;
+    encapsulator.addCommandlineOptions(cmd);
+    prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+
+    if (app.parseCommandLine(cmd, argc, argv))
+    {
+        OFLOG_TRACE (dcmencapLogger, "Checking exclusive options first");
+        if (cmd.hasExclusiveOption())
+        {
+          if (cmd.findOption("--version"))
+          {
+              app.printHeader(OFTrue /*print host identifier*/);
+              COUT << OFendl << "External libraries used: ";
+#ifdef WITH_ZLIB
+              COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
+#else
+              COUT << " none" << OFendl;
+#endif
+              return EXITCODE_NO_ERROR;
+          }
+        }
+        encapsulator.parseArguments(app, cmd);
+    }
+
+    //print resource identifier
+    OFLOG_DEBUG(dcmencapLogger, rcsid << OFendl);
+
+    OFLOG_DEBUG(dcmencapLogger, "making sure data dictionary is loaded");
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFLOG_WARN(dcmencapLogger, "no data dictionary loaded, check environment variable: "
+            << DCM_DICT_ENVIRONMENT_VARIABLE);
+    }
+
+    // read input document and place it into the dataset.
+    // This call will also determine the file type (unless set by command line option).
+    OFLOG_INFO(dcmencapLogger, "reading file '" << encapsulator.getInputFileName() << "'");
+    result = encapsulator.insertEncapsulatedDocument();
+    if (result.bad()) return EXITCODE_INVALID_INPUT_FILE;
+
+    // read series file (if any) and otherwise generate study and series UID
+    result = encapsulator.createIdentifiers();
+    if (result.bad()) return EXITCODE_INVALID_INPUT_FILE;
+
+    // perform document format specific processing (such as reading information from the CDA content)
+    result = encapsulator.formatSpecificProcessing();
+    if (result.bad()) return EXITCODE_INVALID_INPUT_FILE;
+
+    // write DICOM header attributes to dataset
+    result = encapsulator.createHeader();
+    if (result.bad()) return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+
+    // apply command line override keys (if any)
+    result = encapsulator.applyOverrideKeys();
+    if (result.bad()) return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+
+    OFLOG_INFO(dcmencapLogger, "writing encapsulated DICOM object as file '" << encapsulator.getOutputFileName() << "'");
+
+    // write DICOM file
+    result = encapsulator.saveFile();
+    if (result.bad()) return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+
+    OFLOG_INFO(dcmencapLogger, "DICOM encapsulation successful");
+    return EXITCODE_NO_ERROR;
+}
index 62326e745d138cae54e826b9baef5448e4e13859..6acb9893e6c2511c5d482df091dbc23c6249917b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 // if defined, use createValueFromTempFile() for large binary data files
 //#define EXPERIMENTAL_READ_FROM_FILE
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
 #include "dcmtk/ofstd/ofstd.h"
 #include "dcmtk/ofstd/ofconapp.h"
 #include "dcmtk/ofstd/ofstream.h"
index 916b388da32c93a894222fe907f3644d0f92f41f..0225299799542d0407fd3dfe53d93ec96e120275 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2023, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -469,6 +469,9 @@ static OFCondition startConversion(
     cond = i2d.convertNextFrame(inputPlug, ++frameNum);
   }
 
+  // adjust byte order of pixel data to local OW byte order
+  if (cond.good()) cond = i2d.adjustByteOrder(inputFiles.size());
+
   // update offset table if image type is encapsulated
   if (cond.good()) cond = i2d.updateOffsetTable();
 
diff --git a/dcmdata/apps/json2dcm.cc b/dcmdata/apps/json2dcm.cc
new file mode 100644 (file)
index 0000000..e26b0e8
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Tingyan Xu
+ *
+ *  Purpose: Convert JSON DICOM document to binary DICOM file
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"      /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/dcmdata/cmdlnarg.h"
+#include "dcmtk/dcmdata/dcostrmz.h"     /* for dcmZlibCompressionLevel */
+#include "dcmtk/dcmdata/dcfilefo.h"     /* for class DcmFileFormat */
+#include "dcmtk/dcmdata/dcdeftag.h"     /* for tag keys */
+#include "dcmtk/dcmdata/dcuid.h"        /* for UID constants */
+#include "dcmtk/dcmdata/dcdict.h"       /* for the data dictionary */
+#include "dcmtk/dcmdata/dcjsonrd.h"     /* for class DcmJSONReader */
+
+#ifdef WITH_ZLIB
+#include <zlib.h>                       /* for zlibVersion() */
+#endif
+
+#define OFFIS_CONSOLE_APPLICATION "json2dcm"
+#define OFFIS_CONSOLE_DESCRIPTION "Convert JSON document to DICOM file or data set"
+
+/* Error codes */
+
+#define EXITCODE_INVALID_JSON_CONTENT                   65
+#define EXITCODE_BULKDATA_URI_NOT_SUPPORTED             66
+
+static OFLogger json2dcmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
+
+static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
+OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
+
+void addInputOptions(OFCommandLine& cmd)
+{
+    cmd.addGroup("input options:");
+      cmd.addSubGroup("input file format:");
+        cmd.addOption("--read-meta-info",      "+f",   "read meta information if present (default)");
+        cmd.addOption("--ignore-meta-info",    "-f",   "ignore file meta information");
+}
+
+void addProcessOptions(OFCommandLine& cmd)
+{
+    cmd.addGroup("processing options:");
+      cmd.addSubGroup("unique identifiers:");
+        cmd.addOption("--generate-new-uids",   "+Ug",    "generate new Study/Series/SOP Instance UID");
+        cmd.addOption("--dont-overwrite-uids", "-Uo",    "do not overwrite existing UIDs (default)");
+        cmd.addOption("--overwrite-uids",      "+Uo",    "overwrite existing UIDs");
+      cmd.addSubGroup("bulkdata URI handling:");
+        cmd.addOption("--parse-bulkdata-uri",  "+Bu",    "parse Bulkdata URIs (default)");
+        cmd.addOption("--ignore-bulkdata-uri", "-Bu",    "ignore Bulkdata URIs");
+        cmd.addOption("--add-bulkdata-dir",    "+Bd", 1, "[d]irectory: string",
+                                                         "add d to list of permitted bulk data sources");
+      cmd.addSubGroup("handling of arrays with multiple data sets:");
+        cmd.addOption("--array-reject",        "-ar",    "reject multiple data sets (default)");
+        cmd.addOption("--array-select",        "+as", 1, "[n]umber: integer",
+                                                         "select data set n from array");
+        cmd.addOption("--array-sequence",      "+ar",    "store all data sets in private sequence");
+}
+
+void addOutputOptions(OFCommandLine& cmd)
+{
+    cmd.addGroup("output options:");
+      cmd.addSubGroup("output file format:");
+        cmd.addOption("--write-file",          "+F",     "write file format (default)");
+        cmd.addOption("--write-dataset",       "-F",     "write data set without file meta information");
+        cmd.addOption("--update-meta-info",    "+Fu",    "update particular file meta information");
+      cmd.addSubGroup("output transfer syntax:");
+        cmd.addOption("--write-xfer-same",     "+t=",    "write with same TS as input (default)");
+        cmd.addOption("--write-xfer-little",   "+te",    "write with explicit VR little endian TS");
+        cmd.addOption("--write-xfer-big",      "+tb",    "write with explicit VR big endian TS");
+        cmd.addOption("--write-xfer-implicit", "+ti",    "write with implicit VR little endian TS");
+#ifdef WITH_ZLIB
+        cmd.addOption("--write-xfer-deflated", "+td",    "write with deflated expl. VR little endian TS");
+#endif
+      cmd.addSubGroup("error handling:");
+        cmd.addOption("--stop-on-error",       "-E",     "do not write if document is invalid (default)");
+        cmd.addOption("--ignore-errors",       "+E",     "attempt to write even if document is invalid");
+      cmd.addSubGroup("post-1993 value representations:");
+        cmd.addOption("--enable-new-vr",       "+u",     "enable support for new VRs (UN/UT) (default)");
+        cmd.addOption("--disable-new-vr",      "-u",     "disable support for new VRs, convert to OB");
+      cmd.addSubGroup("length encoding in sequences and items:");
+        cmd.addOption("--length-explicit",     "+e",     "write with explicit lengths (default)");
+        cmd.addOption("--length-undefined",    "-e",     "write with undefined lengths");
+      cmd.addSubGroup("charset handling:");
+        cmd.addOption("--charset-accept",      "+c",     "write with the given charset in JSON (default)");
+        cmd.addOption("--charset-replace",     "-c",     "replace the given charset in JSON with UTF-8");
+#ifdef WITH_ZLIB
+      cmd.addSubGroup("deflate compression level (only with --write-xfer-deflated):");
+        cmd.addOption("--compression-level",   "+cl", 1, "[l]evel: integer (default: 6)",
+                                                         "0=uncompressed, 1=fastest, 9=best compression");
+#endif
+}
+
+#define SHORTCOL 3
+#define LONGCOL 21
+
+void addJSON2DCMCommandlineOptions(OFCommandLine& cmd)
+{
+    cmd.setOptionColumns(LONGCOL, SHORTCOL);
+    cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+
+    cmd.addParam("jsonfile-in", "JSON input filename to be converted\n(\"-\" for stdin)");
+    cmd.addParam("dcmfile-out", "DICOM output filename\n(\"-\" for stdout)");
+
+    cmd.addGeneralOptions(LONGCOL, SHORTCOL);
+    OFLog::addOptions(cmd);
+    addInputOptions(cmd);
+    addProcessOptions(cmd);
+    addOutputOptions(cmd);
+}
+
+/**
+ * function for parsing commandline arguments
+ */
+OFCondition parseArguments(
+    OFConsoleApplication& app,
+    OFCommandLine& cmd,
+    OFBool& opt_generateUIDs,
+    OFBool& opt_overwriteUIDs,
+    E_TransferSyntax& opt_xfer,
+    E_EncodingType& opt_enctype,
+    OFBool& opt_replaceCharset,
+    E_FileWriteMode& opt_writeMode,
+    const char*& opt_ifname,
+    const char*& opt_ofname,
+    DcmJSONReader& jsonReader
+)
+{
+    cmd.getParam(1, opt_ifname);
+    cmd.getParam(2, opt_ofname);
+
+    OFLog::configureFromCommandLine(cmd, app);
+
+    /* input options */
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--read-meta-info"))
+        jsonReader.setIgnoreMetaInfoPolicy(OFFalse);
+    if (cmd.findOption("--ignore-meta-info"))
+        jsonReader.setIgnoreMetaInfoPolicy(OFTrue);
+    cmd.endOptionBlock();
+
+    /* processing options */
+    if (cmd.findOption("--generate-new-uids"))
+        opt_generateUIDs = OFTrue;
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--dont-overwrite-uids"))
+    {
+        app.checkDependence("--dont-overwrite-uids", "--generate-new-uids", opt_generateUIDs);
+        opt_overwriteUIDs = OFFalse;
+    }
+    if (cmd.findOption("--overwrite-uids"))
+    {
+        app.checkDependence("--overwrite-uids", "--generate-new-uids", opt_generateUIDs);
+        opt_overwriteUIDs = OFTrue;
+    }
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--ignore-bulkdata-uri"))
+    {
+        jsonReader.setIgnoreBulkdataURIPolicy(OFTrue);
+    }
+    if (cmd.findOption("--parse-bulkdata-uri"))
+    {
+        jsonReader.setIgnoreBulkdataURIPolicy(OFFalse);
+    }
+    cmd.endOptionBlock();
+
+    if (cmd.findOption("--add-bulkdata-dir", 0, OFCommandLine::FOM_First))
+    {
+        OFCondition result;
+        const char *current = NULL;
+        do
+        {
+            app.checkValue(cmd.getValue(current));
+            result = jsonReader.addPermittedBulkdataPath(current);
+            if (result.bad()) return result;
+        } while (cmd.findOption("--add-bulkdata-dir", 0, OFCommandLine::FOM_Next));
+    }
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--array-reject"))
+    {
+        jsonReader.setArrayHandlingPolicy(-1);
+    }
+    if (cmd.findOption("--array-sequence"))
+    {
+        jsonReader.setArrayHandlingPolicy(0);
+    }
+    if (cmd.findOption("--array-select"))
+    {
+        OFCmdSignedInt arrayHandling = -1;
+        cmd.getValueAndCheckMin(arrayHandling, 1);
+        jsonReader.setArrayHandlingPolicy(arrayHandling);
+    }
+    cmd.endOptionBlock();
+
+    /* output options */
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--write-file"))
+        opt_writeMode = EWM_fileformat;
+    if (cmd.findOption("--write-dataset"))
+        opt_writeMode = EWM_dataset;
+    cmd.endOptionBlock();
+
+    if (cmd.findOption("--update-meta-info"))
+    {
+        app.checkConflict("--update-meta-info", "--write-dataset", opt_writeMode == EWM_dataset);
+        opt_writeMode = EWM_updateMeta;
+    }
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--write-xfer-same"))
+        opt_xfer = EXS_Unknown;
+    if (cmd.findOption("--write-xfer-little"))
+        opt_xfer = EXS_LittleEndianExplicit;
+    if (cmd.findOption("--write-xfer-big"))
+        opt_xfer = EXS_BigEndianExplicit;
+    if (cmd.findOption("--write-xfer-implicit"))
+        opt_xfer = EXS_LittleEndianImplicit;
+#ifdef WITH_ZLIB
+    if (cmd.findOption("--write-xfer-deflated"))
+        opt_xfer = EXS_DeflatedLittleEndianExplicit;
+#endif
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--stop-on-error"))
+        jsonReader.setStopOnErrorPolicy(OFTrue);
+    if (cmd.findOption("--ignore-errors"))
+        jsonReader.setStopOnErrorPolicy(OFFalse);
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--enable-new-vr"))
+        dcmEnableGenerationOfNewVRs();
+    if (cmd.findOption("--disable-new-vr"))
+        dcmDisableGenerationOfNewVRs();
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--length-explicit"))
+        opt_enctype = EET_ExplicitLength;
+    if (cmd.findOption("--length-undefined"))
+        opt_enctype = EET_UndefinedLength;
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--charset-accept"))
+        opt_replaceCharset = OFFalse;
+    if (cmd.findOption("--charset-replace"))
+        opt_replaceCharset = OFTrue;
+    cmd.endOptionBlock();
+
+#ifdef WITH_ZLIB
+    if (cmd.findOption("--compression-level"))
+    {
+        OFCmdUnsignedInt comprLevel = 0;
+        app.checkDependence("--compression-level", "--write-xfer-deflated", opt_xfer == EXS_DeflatedLittleEndianExplicit);
+        app.checkValue(cmd.getValueAndCheckMinMax(comprLevel, 0, 9));
+        dcmZlibCompressionLevel.set(OFstatic_cast(int, comprLevel));
+    }
+#endif
+
+    return EC_Normal;
+}
+
+void generateUIDs(DcmItem *dataset, OFBool overwriteUIDs, E_FileWriteMode& writeMode)
+{
+    char uid[100];
+    if (overwriteUIDs || !dataset->tagExistsWithValue(DCM_StudyInstanceUID))
+    {
+        OFLOG_INFO(json2dcmLogger, "generating new Study Instance UID");
+        dataset->putAndInsertString(DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT));
+    }
+    if (overwriteUIDs || !dataset->tagExistsWithValue(DCM_SeriesInstanceUID))
+    {
+        OFLOG_INFO(json2dcmLogger, "generating new Series Instance UID");
+        dataset->putAndInsertString(DCM_SeriesInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT));
+    }
+    if (overwriteUIDs || !dataset->tagExistsWithValue(DCM_SOPInstanceUID))
+    {
+        OFLOG_INFO(json2dcmLogger, "generating new SOP Instance UID");
+        dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
+
+        /* make sure that the file meta information is updated correspondingly */
+        if (writeMode == EWM_fileformat)
+            writeMode = EWM_updateMeta;
+    }
+}
+
+void updateCharacterSet(DcmItem *dataset, const char *ifname, OFBool replaceCharset)
+{
+    OFString allowedCharset = "ISO_IR 192";
+    OFString asciiCharset = "ISO_IR 6";
+    const char *elemValue;
+    OFCondition result = dataset->findAndGetString(DCM_SpecificCharacterSet, elemValue, OFTrue /*searchIntoSub*/);
+    if (replaceCharset)
+    {
+        if (result.bad() || elemValue == NULL)
+        {
+            OFLOG_WARN(json2dcmLogger, "JSON file '" << ifname << "' does not specify a character set, it will be set to UTF-8 ('" << allowedCharset << "')");
+            dataset->putAndInsertString(DCM_SpecificCharacterSet, allowedCharset.c_str());
+        }
+        else if (allowedCharset.compare(elemValue) != 0)
+        {
+            OFLOG_WARN(json2dcmLogger, "JSON file '" << ifname << "' specifies a character set other than UTF-8, it will be set to UTF-8 ('" << allowedCharset << "')");
+            dataset->putAndInsertString(DCM_SpecificCharacterSet, allowedCharset.c_str());
+        }
+    }
+    else
+    {
+        if ((result.bad() || elemValue == NULL))
+        {
+            if (dataset->containsExtendedCharacters())
+            {
+                // JSON dataset contains non-ASCII characters but no specific character set
+                OFLOG_WARN(json2dcmLogger, "JSON file '" << ifname << "' does not specify a character set, the file is encoded in UTF-8 ('" << allowedCharset << "')");
+            }
+        }
+        else if (allowedCharset.compare(elemValue) != 0)
+        {
+            // JSON dataset specifies a specific character set other then ISO_IR 192
+            if (dataset->containsExtendedCharacters() || (asciiCharset.compare(elemValue) != 0))
+            {
+                // JSON dataset is not ASCII (ISO_IR 6) either
+                OFLOG_WARN(json2dcmLogger, "JSON file '" << ifname << "' specifies the character set '"
+                    << elemValue << "' but the file is encoded in UTF-8 ('" << allowedCharset << "')");
+            }
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    OFBool opt_generateUIDs = OFFalse;
+    OFBool opt_overwriteUIDs = OFFalse;
+    E_TransferSyntax opt_xfer = EXS_Unknown;
+    E_EncodingType opt_enctype = EET_ExplicitLength;
+    OFBool opt_replaceCharset = OFFalse;
+    E_FileWriteMode opt_writeMode = EWM_fileformat;
+
+    const char *opt_ifname = NULL;
+    const char *opt_ofname = NULL;
+
+    /* set-up command line parameters and options */
+    OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, OFFIS_CONSOLE_DESCRIPTION, rcsid);
+    OFCommandLine cmd;
+
+    // add supported command line options
+    addJSON2DCMCommandlineOptions(cmd);
+
+    // evaluate command line
+    prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
+    if (app.parseCommandLine(cmd, argc, argv))
+    {
+        // checking exclusive options first
+        if (cmd.hasExclusiveOption())
+        {
+            if (cmd.findOption("--version"))
+            {
+                app.printHeader(OFTrue /*print host identifier*/);
+                COUT << OFendl << "External libraries used:";
+#ifdef WITH_ZLIB
+                COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
+#else
+                COUT << " none" << OFendl;
+#endif
+                return EXITCODE_NO_ERROR;
+            }
+        }
+    }
+
+    /* print resource identifier */
+    OFLOG_DEBUG(json2dcmLogger, rcsid << OFendl);
+
+    /* make sure data dictionary is loaded */
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFLOG_WARN(json2dcmLogger, "no data dictionary loaded, check environment variable: "
+            << DCM_DICT_ENVIRONMENT_VARIABLE);
+    }
+
+    DcmFileFormat fileformat;
+    DcmJSONReader jsonReader;
+
+    /* command line parameters and options */
+    OFCondition result = parseArguments(
+        app, cmd,
+        opt_generateUIDs,
+        opt_overwriteUIDs,
+        opt_xfer,
+        opt_enctype,
+        opt_replaceCharset,
+        opt_writeMode,
+        opt_ifname,
+        opt_ofname,
+        jsonReader
+    );
+
+    if (result.bad())
+        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
+
+    // check filenames
+    if ((opt_ifname == NULL) || (strlen(opt_ifname) == 0))
+    {
+        OFLOG_ERROR(json2dcmLogger, OFFIS_CONSOLE_APPLICATION << ": invalid input filename: <empty string>");
+        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
+    }
+    if ((opt_ofname == NULL) || (strlen(opt_ofname) == 0))
+    {
+        OFLOG_ERROR(json2dcmLogger, OFFIS_CONSOLE_APPLICATION << ": invalid output filename: <empty string>");
+        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
+    }
+
+    // read JSON file and convert to DICOM
+    OFLOG_INFO(json2dcmLogger, "reading JSON input file: " << opt_ifname);
+    result = jsonReader.readAndConvertJSONFile(fileformat, opt_ifname);
+    if (result.bad())
+    {
+        if (result == EC_BulkDataURINotSupported)
+            return EXITCODE_BULKDATA_URI_NOT_SUPPORTED;
+        else if (result == EC_InvalidFilename)
+            return EXITCODE_CANNOT_READ_INPUT_FILE;
+        else
+            return EXITCODE_INVALID_JSON_CONTENT;
+    }
+
+    // generate new UIDs (if required)
+    if (opt_generateUIDs)
+    {
+        generateUIDs(fileformat.getDataset(), opt_overwriteUIDs, opt_writeMode);
+    }
+
+    // check and update SpecificCharacterSet
+    updateCharacterSet(fileformat.getDataset(), opt_ifname, opt_replaceCharset);
+
+    // determine the transfer syntax for writing the file
+    if (opt_xfer == EXS_Unknown)
+    {
+        /* use Explicit VR Little Endian as default if no transfer syntax is given otherwise */
+        if (jsonReader.getTransferSyntax() == EXS_Unknown)
+            opt_xfer = EXS_LittleEndianExplicit;
+        else
+            opt_xfer = jsonReader.getTransferSyntax();
+    }
+
+    // check whether it is possible to write the file in the requested transfer syntax
+    if (fileformat.canWriteXfer(opt_xfer))
+    {
+        // encapsulated pixel data requires a DICOM file, in this case ignore --write-dataset
+        if ((opt_writeMode == EWM_dataset) && DcmXfer(opt_xfer).usesEncapsulatedFormat())
+        {
+            OFLOG_WARN(json2dcmLogger, "encapsulated pixel data require file format, ignoring --write-dataset");
+            opt_writeMode = EWM_fileformat;
+        }
+
+        OFLOG_INFO(json2dcmLogger, "writing DICOM output file: " << opt_ofname);
+        result = fileformat.saveFile(opt_ofname, opt_xfer, opt_enctype, EGL_withoutGL, EPD_noChange,
+            OFstatic_cast(Uint32, 0), OFstatic_cast(Uint32, 0), opt_writeMode);
+
+        if (result.bad())
+        {
+            OFLOG_ERROR(json2dcmLogger, result.text() << ": writing file: " << opt_ofname);
+            return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+        }
+    }
+    else
+    {
+        OFLOG_ERROR(json2dcmLogger, "no conversion to transfer syntax " << DcmXfer(opt_xfer).getXferName() << " possible!");
+        return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+    }
+
+    return 0;
+}
+
index 26d288f63440c064e1c562007cb9cf8386bea108..0cdccd83c79ace30060300faf3dd77c12383044a 100644 (file)
@@ -618,7 +618,9 @@ OFCondition MdfDatasetManager::saveFile(const char* file_name,
         {
             opt_xfer = EXS_LittleEndianExplicit;
         }
-        /* write DICOM file */
+        /* write DICOM file. We deliberately use write mode EWM_fileformat here because
+         * EWM_createNewMeta would break the "--no-meta-uid" command line option
+         */
         result = dfile->saveFile(file_name,
                                  opt_xfer,
                                  opt_enctype,
@@ -626,7 +628,7 @@ OFCondition MdfDatasetManager::saveFile(const char* file_name,
                                  opt_padenc,
                                  OFstatic_cast(Uint32, opt_filepad),
                                  OFstatic_cast(Uint32, opt_itempad),
-                                 (opt_dataset) ? EWM_dataset : EWM_createNewMeta);
+                                 (opt_dataset) ? EWM_dataset : EWM_fileformat);
     }
     else
     {
index 95839753237fb82e0d4f1469fe3695783b50b355..4fefe48fa2bfca0807d5a85859725660e0a5d83e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2005-2019, OFFIS e.V.
+ *  Copyright (C) 2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *  Module:  dcmdata
  *
- *  Author:  Marco Eichelberg, Pedro Arizpe
+ *  Authors: Marco Eichelberg
  *
- *  Purpose: Encapsulate PDF file into a DICOM file
+ *  Purpose: Proxy stub that calls dcmencap
  *
  */
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
-#include "dcmtk/dcmdata/dctk.h"
-#include "dcmtk/dcmdata/dcencdoc.h"
-#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/ofstd/ofstub.h"
+#include "dcmtk/ofstd/ofstd.h"
+#include <cstring>
 
-#ifdef WITH_ZLIB
-#include <zlib.h>        /* for zlibVersion() */
-#endif
-
-#define OFFIS_CONSOLE_APPLICATION "pdf2dcm"
-
-static OFLogger pdf2dcmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
-
-static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
-OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
-
-int main(int argc, char *argv[])
+int main(int argc, char** argv)
 {
-  OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Encapsulate PDF file into DICOM format", rcsid);
-  OFCommandLine cmd;
-  int errorCode = EXITCODE_NO_ERROR;
-  OFCondition result = EC_Normal;
-  DcmFileFormat fileformat;
-  DcmEncapsulatedDocument encapsulator;
-
-  OFLOG_TRACE(pdf2dcmLogger, "Including necessary options");
-  encapsulator.addPDFCommandlineOptions(cmd);
-  OFLOG_TRACE(pdf2dcmLogger, "Evaluating command line");
-  prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
-
-  if (app.parseCommandLine(cmd, argc, argv)) {
-    OFLOG_TRACE(pdf2dcmLogger, "Checking exclusive options first");
-    if (cmd.hasExclusiveOption())
-    {
-      if (cmd.findOption("--version"))
-      {
-        app.printHeader(OFTrue /*print host identifier*/);
-        COUT << OFendl << "External libraries used: ";
-#ifdef WITH_ZLIB
-        COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
-#else
-        COUT << " none" << OFendl;
-#endif
-        return EXITCODE_NO_ERROR;
-      }
-    }
-    encapsulator.parseArguments(app, cmd);
-  }
-  //print resource identifier
-  OFLOG_DEBUG(pdf2dcmLogger, rcsid << OFendl);
-
-  OFLOG_DEBUG(pdf2dcmLogger, "making sure data dictionary is loaded");
-  if (!dcmDataDict.isDictionaryLoaded())
-  {
-    OFLOG_WARN(pdf2dcmLogger, "no data dictionary loaded, check environment variable: "
-      << DCM_DICT_ENVIRONMENT_VARIABLE);
-  }
-  OFLOG_DEBUG(pdf2dcmLogger, "Creating identifiers (and reading series data)");
-  result = encapsulator.createIdentifiers(pdf2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_FATAL(pdf2dcmLogger, "There was an error while reading the series data");
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  OFLOG_INFO(pdf2dcmLogger, "creating encapsulated PDF object");
-  errorCode = encapsulator.insertEncapsulatedDocument(fileformat.getDataset(), pdf2dcmLogger);
-  if (errorCode != EXITCODE_NO_ERROR)
-  {
-    OFLOG_ERROR(pdf2dcmLogger, "unable to create PDF encapsulation to DICOM format");
-    return errorCode;
-  }
-  OFLOG_INFO(pdf2dcmLogger, "Generating an instance number that is guaranteed to be unique within a series.");
-  result = encapsulator.createHeader(fileformat.getDataset(), pdf2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_ERROR(pdf2dcmLogger, "unable to create DICOM header: " << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(pdf2dcmLogger, "writing encapsulated PDF object as file " << encapsulator.getOutputFileName());
-
-  OFLOG_INFO(pdf2dcmLogger, "Check if new output transfer syntax is possible");
-
-  DcmXfer opt_oxferSyn(encapsulator.getTransferSyntax());
-
-  fileformat.getDataset()->chooseRepresentation(encapsulator.getTransferSyntax(), NULL);
-  if (fileformat.getDataset()->canWriteXfer(encapsulator.getTransferSyntax()))
-  {
-    OFLOG_INFO(pdf2dcmLogger, "Output transfer syntax " << opt_oxferSyn.getXferName() << " can be written");
-  }
-  else {
-    OFLOG_ERROR(pdf2dcmLogger, "No conversion to transfer syntax " << opt_oxferSyn.getXferName() << " possible!");
-    return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-  }
-  OFLOG_INFO(pdf2dcmLogger, "Checking for DICOM key overriding");
-  result = encapsulator.applyOverrideKeys(fileformat.getDataset());
-  if (result.bad())
-  {
-    OFLOG_ERROR(pdf2dcmLogger, "There was a problem while overriding a key:" << OFendl
-      << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(pdf2dcmLogger, "write converted DICOM file with metaheader");
-  result = encapsulator.saveFile(fileformat);
-  if (result.bad())
-  {
-    OFLOG_ERROR(pdf2dcmLogger, result.text() << ": writing file: " << encapsulator.getOutputFileName());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-
-  OFLOG_INFO(pdf2dcmLogger, "PDF encapsulation successful");
-
-  return EXITCODE_NO_ERROR;
+    // create an argv array that is one entry larger than the one specified by the user
+    char **my_argv = new char *[argc+2];
+    char filetype[100];
+    OFStandard::strlcpy(filetype, "--filetype-pdf", sizeof(filetype));
+
+    // copy arguments, then add file type argument and NULL pointer
+    memcpy(my_argv, argv, argc * sizeof(char *));
+    my_argv[argc] = filetype;
+    my_argv[argc+1] = NULL;
+
+    // call stub
+    int result = OFstub_main(argc+1, my_argv, "pdf2dcm", "dcmencap");
+
+    // clean up (Windows only, on Posix systems the stub will not return)
+    delete[] my_argv;
+    return result;
 }
index d684679d7f32180d7eced4f76ce6b6359358b2f5..13bf34a9aa6d143dc04dc36525ef0478ff20f9bb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2019, OFFIS e.V.
+ *  Copyright (C) 2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
  *
  *  Module:  dcmdata
  *
- *  Author:  Pedro Arizpe
+ *  Authors: Marco Eichelberg
  *
- *  Purpose: Encapsulate STL file into a DICOM file
+ *  Purpose: Proxy stub that calls dcmencap
  *
  */
 
-#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first*/
-#include "dcmtk/dcmdata/dctk.h"
-#include "dcmtk/dcmdata/dcencdoc.h"
-#include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofstub.h"
+#include "dcmtk/ofstd/ofstd.h"
+#include <cstring>
 
-#ifdef WITH_ZLIB
-#include <zlib.h>        /* for zlibVersion() */
-#endif
-
-#define OFFIS_CONSOLE_APPLICATION "stl2dcm"
-
-static OFLogger stl2dcmLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
-
-static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
-OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
-
-int main(int argc, char *argv[])
+int main(int argc, char** argv)
 {
-  OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Encapsulate STL file into DICOM format", rcsid);
-  OFCommandLine cmd;
-  int errorCode = EXITCODE_NO_ERROR;
-  OFCondition result = EC_Normal;
-  DcmFileFormat fileformat;
-  DcmEncapsulatedDocument encapsulator;
-
-  OFLOG_TRACE(stl2dcmLogger, "Including necessary options");
-  encapsulator.addSTLCommandlineOptions(cmd);
-  OFLOG_TRACE(stl2dcmLogger, "Evaluating command line");
-  prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
-
-  if (app.parseCommandLine(cmd, argc, argv)) {
-    OFLOG_TRACE(stl2dcmLogger, "Checking exclusive options first");
-    if (cmd.hasExclusiveOption())
-    {
-      if (cmd.findOption("--version"))
-      {
-        app.printHeader(OFTrue /*print host identifier*/);
-        COUT << OFendl << "External libraries used: ";
-#ifdef WITH_ZLIB
-        COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
-#else
-        COUT << " none" << OFendl;
-#endif
-        return EXITCODE_NO_ERROR;
-      }
-    }
-    encapsulator.parseArguments(app, cmd);
-  }
-  //print resource identifier
-  OFLOG_DEBUG(stl2dcmLogger, rcsid << OFendl);
-
-  OFLOG_DEBUG(stl2dcmLogger, "making sure data dictionary is loaded");
-  if (!dcmDataDict.isDictionaryLoaded())
-  {
-    OFLOG_WARN(stl2dcmLogger, "no data dictionary loaded, check environment variable: "
-      << DCM_DICT_ENVIRONMENT_VARIABLE);
-  }
-  OFLOG_DEBUG(stl2dcmLogger, "Creating identifiers (and reading series data)");
-  result = encapsulator.createIdentifiers(stl2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_FATAL(stl2dcmLogger, "There was an error while reading the series data");
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  OFLOG_INFO(stl2dcmLogger, "creating encapsulated STL object");
-  errorCode = encapsulator.insertEncapsulatedDocument(fileformat.getDataset(), stl2dcmLogger);
-  if (errorCode != EXITCODE_NO_ERROR)
-  {
-    OFLOG_ERROR(stl2dcmLogger, "unable to create STL encapsulation to DICOM format");
-    return errorCode;
-  }
-  OFLOG_INFO(stl2dcmLogger, "Generating an instance number that is guaranteed to be unique within a series.");
-  result = encapsulator.createHeader(fileformat.getDataset(), stl2dcmLogger);
-  if (result.bad())
-  {
-    OFLOG_ERROR(stl2dcmLogger, "unable to create DICOM header: " << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(stl2dcmLogger, "writing encapsulated STL object as file " << encapsulator.getOutputFileName());
-
-  OFLOG_INFO(stl2dcmLogger, "Check if new output transfer syntax is possible");
-
-  DcmXfer opt_oxferSyn(encapsulator.getTransferSyntax());
-
-  fileformat.getDataset()->chooseRepresentation(encapsulator.getTransferSyntax(), NULL);
-  if (fileformat.getDataset()->canWriteXfer(encapsulator.getTransferSyntax()))
-  {
-    OFLOG_INFO(stl2dcmLogger, "Output transfer syntax " << opt_oxferSyn.getXferName() << " can be written");
-  }
-  else {
-    OFLOG_ERROR(stl2dcmLogger, "No conversion to transfer syntax " << opt_oxferSyn.getXferName() << " possible!");
-    return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-  }
-  OFLOG_INFO(stl2dcmLogger, "Checking for DICOM key overriding");
-  result = encapsulator.applyOverrideKeys(fileformat.getDataset());
-  if (result.bad())
-  {
-    OFLOG_ERROR(stl2dcmLogger, "There was a problem while overriding a key:" << OFendl
-      << result.text());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  OFLOG_INFO(stl2dcmLogger, "write converted DICOM file with metaheader");
-  result = encapsulator.saveFile(fileformat);
-  if (result.bad())
-  {
-    OFLOG_ERROR(stl2dcmLogger, result.text() << ": writing file: " << encapsulator.getOutputFileName());
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-
-  OFLOG_INFO(stl2dcmLogger, "STL encapsulation successful");
-
-  return EXITCODE_NO_ERROR;
+    // create an argv array that is one entry larger than the one specified by the user
+    char **my_argv = new char *[argc+2];
+    char filetype[100];
+    OFStandard::strlcpy(filetype, "--filetype-stl", sizeof(filetype));
+
+    // copy arguments, then add file type argument and NULL pointer
+    memcpy(my_argv, argv, argc * sizeof(char *));
+    my_argv[argc] = filetype;
+    my_argv[argc+1] = NULL;
+
+    // call stub
+    int result = OFstub_main(argc+1, my_argv, "stl2dcm", "dcmencap");
+
+    // clean up (Windows only, on Posix systems the stub will not return)
+    delete[] my_argv;
+    return result;
 }
index 44f771e81e3bf6150a17e1c4e957543733d7a1e9..0798e72a3eee1197024e33b75ffc2c9d9e95ff27 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 1994-2024, OFFIS e.V.
+#  Copyright (C) 1994-2025, OFFIS e.V.
 #  All rights reserved.  See COPYRIGHT file for details.
 #
 #  This software and supporting documentation were developed by
@@ -21,8 +21,8 @@
 # DICONDE (Digital Imaging and Communication in Nondestructive Evaluation) and
 # DICOS (Digital Imaging and Communications in Security) standard.
 #
-# Generated automatically from DICOM PS 3.6-2024e and PS 3.7-2024e.
-# File created on 2024-11-16 10:17:21 by J. Riesmeier on thinkpad2.
+# Generated automatically from DICOM PS 3.6-2025e and PS 3.7-2025e.
+# File created on 2025-11-21 11:51:05 by J. Riesmeier on thinkpad2.
 #
 # In addition, the data dictionary entries from the following final text
 # supplements and correction items (CP) have been incorporated:
 (0008,119B)    SQ      FailedStudySequence     1       DICOM
 (0008,1200)    SQ      StudiesContainingOtherReferencedInstancesSequence       1       DICOM
 (0008,1250)    SQ      RelatedSeriesSequence   1       DICOM
+(0008,1301)    SQ      PrincipalDiagnosisCodeSequence  1       DICOM
+(0008,1302)    SQ      PrimaryDiagnosisCodeSequence    1       DICOM
+(0008,1303)    SQ      SecondaryDiagnosesCodeSequence  1       DICOM
+(0008,1304)    SQ      HistologicalDiagnosesCodeSequence       1       DICOM
 (0008,2111)    ST      DerivationDescription   1       DICOM
 (0008,2112)    SQ      SourceImageSequence     1       DICOM
 (0008,2120)    SH      StageName       1       DICOM
 (0008,9459)    FL      RecommendedDisplayFrameRateInFloat      1       DICOM
 (0008,9460)    CS      SkipFrameRangeFlag      1       DICOM
 (0010,0010)    PN      PatientName     1       DICOM
+(0010,0011)    SQ      PersonNamesToUseSequence        1       DICOM
+(0010,0012)    LT      NameToUse       1       DICOM
+(0010,0013)    UT      NameToUseComment        1       DICOM
+(0010,0014)    SQ      ThirdPersonPronounsSequence     1       DICOM
+(0010,0015)    SQ      PronounCodeSequence     1       DICOM
+(0010,0016)    UT      PronounComment  1       DICOM
 (0010,0020)    LO      PatientID       1       DICOM
 (0010,0021)    LO      IssuerOfPatientID       1       DICOM
 (0010,0022)    CS      TypeOfPatientID 1       DICOM
 (0010,0034)    LO      PatientDeathDateInAlternativeCalendar   1       DICOM
 (0010,0035)    CS      PatientAlternativeCalendar      1       DICOM
 (0010,0040)    CS      PatientSex      1       DICOM
+(0010,0041)    SQ      GenderIdentitySequence  1       DICOM
+(0010,0042)    UT      SexParametersForClinicalUseCategoryComment      1       DICOM
+(0010,0043)    SQ      SexParametersForClinicalUseCategorySequence     1       DICOM
+(0010,0044)    SQ      GenderIdentityCodeSequence      1       DICOM
+(0010,0045)    UT      GenderIdentityComment   1       DICOM
+(0010,0046)    SQ      SexParametersForClinicalUseCategoryCodeSequence 1       DICOM
+(0010,0047)    UR      SexParametersForClinicalUseCategoryReference    1-n     DICOM
 (0010,0050)    SQ      PatientInsurancePlanCodeSequence        1       DICOM
 (0010,0101)    SQ      PatientPrimaryLanguageCodeSequence      1       DICOM
 (0010,0102)    SQ      PatientPrimaryLanguageModifierCodeSequence      1       DICOM
 (0010,2152)    LO      RegionOfResidence       1       DICOM
 (0010,2154)    SH      PatientTelephoneNumbers 1-n     DICOM
 (0010,2155)    LT      PatientTelecomInformation       1       DICOM
-(0010,2160)    SH      EthnicGroup     1       DICOM
 (0010,2161)    SQ      EthnicGroupCodeSequence 1       DICOM
+(0010,2162)    UC      EthnicGroups    1-n     DICOM
 (0010,2180)    SH      Occupation      1       DICOM
 (0010,21A0)    CS      SmokingStatus   1       DICOM
 (0010,21B0)    LT      AdditionalPatientHistory        1       DICOM
 (0014,40A0)    LO      ImageQualityIndicatorType       1-n     DICOM/DICONDE
 (0014,40A1)    LO      ImageQualityIndicatorMaterial   1-n     DICOM/DICONDE
 (0014,40A2)    LO      ImageQualityIndicatorSize       1-n     DICOM/DICONDE
+(0014,4101)    SQ      WaveDimensionsDefinitionSequence        1       DICOM/DICONDE
+(0014,4102)    US      WaveDimensionNumber     1       DICOM/DICONDE
+(0014,4103)    LO      WaveDimensionDescription        1       DICOM/DICONDE
+(0014,4104)    US      WaveDimensionUnit       1       DICOM/DICONDE
+(0014,4105)    CS      WaveDimensionValueType  1       DICOM/DICONDE
+(0014,4106)    SQ      WaveDimensionValuesSequence     1-n     DICOM/DICONDE
+(0014,4107)    US      ReferencedWaveDimension 1       DICOM/DICONDE
+(0014,4108)    SL      IntegerNumericValue     1       DICOM/DICONDE
+(0014,4109)    OB      ByteNumericValue        1       DICOM/DICONDE
+(0014,410A)    OW      ShortNumericValue       1       DICOM/DICONDE
+(0014,410B)    OF      SinglePrecisionFloatingPointNumericValue        1       DICOM/DICONDE
+(0014,410C)    OD      DoublePrecisionFloatingPointNumericValue        1       DICOM/DICONDE
 (0014,5002)    IS      LINACEnergy     1       DICOM/DICONDE
 (0014,5004)    IS      LINACOutput     1       DICOM/DICONDE
 (0014,5100)    US      ActiveAperture  1       DICOM/DICONDE
 (0040,A030)    DT      VerificationDateTime    1       DICOM
 (0040,A032)    DT      ObservationDateTime     1       DICOM
 (0040,A033)    DT      ObservationStartDateTime        1       DICOM
+(0040,A034)    DT      EffectiveStartDateTime  1       DICOM
+(0040,A035)    DT      EffectiveStopDateTime   1       DICOM
 (0040,A040)    CS      ValueType       1       DICOM
 (0040,A043)    SQ      ConceptNameCodeSequence 1       DICOM
 (0040,A050)    CS      ContinuityOfContent     1       DICOM
 (0040,A807)    SQ      TableColumnDefinitionSequence   1       DICOM
 (0040,A808)    SQ      CellValuesSequence      1       DICOM
 (0040,B020)    SQ      WaveformAnnotationSequence      1       DICOM
+(0040,B030)    SQ      StructuredWaveformAnnotationSequence    1       DICOM
+(0040,B031)    SQ      WaveformAnnotationDisplaySelectionSequence      1       DICOM
+(0040,B032)    US      ReferencedMontageIndex  1       DICOM
+(0040,B033)    SQ      WaveformTextualAnnotationSequence       1       DICOM
+(0040,B034)    DT      AnnotationDateTime      1       DICOM
+(0040,B035)    SQ      DisplayedWaveformSegmentSequence        1       DICOM
+(0040,B036)    DT      SegmentDefinitionDateTime       1       DICOM
+(0040,B037)    SQ      MontageActivationSequence       1       DICOM
+(0040,B038)    DS      MontageActivationTimeOffset     1       DICOM
+(0040,B039)    SQ      WaveformMontageSequence 1       DICOM
+(0040,B03A)    IS      ReferencedMontageChannelNumber  1       DICOM
+(0040,B03B)    LT      MontageName     1       DICOM
+(0040,B03C)    SQ      MontageChannelSequence  1       DICOM
+(0040,B03D)    US      MontageIndex    1       DICOM
+(0040,B03E)    IS      MontageChannelNumber    1       DICOM
+(0040,B03F)    LO      MontageChannelLabel     1       DICOM
+(0040,B040)    SQ      MontageChannelSourceCodeSequence        1       DICOM
+(0040,B041)    SQ      ContributingChannelSourcesSequence      1       DICOM
+(0040,B042)    FL      ChannelWeight   1       DICOM
 (0040,DB00)    CS      TemplateIdentifier      1       DICOM
 (0040,DB73)    UL      ReferencedContentItemIdentifier 1-n     DICOM
 (0040,E001)    ST      HL7InstanceIdentifier   1       DICOM
 (0044,0108)    UI      ReferencedAssertionUID  1       DICOM
 (0044,0109)    SQ      ApprovalSubjectSequence 1       DICOM
 (0044,010A)    SQ      OrganizationalRoleCodeSequence  1       DICOM
+(0044,0110)    SQ      RTAssertionsSequence    1       DICOM
 (0046,0012)    LO      LensDescription 1       DICOM
 (0046,0014)    SQ      RightLensSequence       1       DICOM
 (0046,0015)    SQ      LeftLensSequence        1       DICOM
 (0048,0301)    CS      PixelOriginInterpretation       1       DICOM
 (0048,0302)    UL      NumberOfOpticalPaths    1       DICOM
 (0048,0303)    UL      TotalPixelMatrixFocalPlanes     1       DICOM
+(0048,0304)    CS      TilesOverlap    1       DICOM
 (0050,0004)    CS      CalibrationImage        1       DICOM
 (0050,0010)    SQ      DeviceSequence  1       DICOM
 (0050,0012)    SQ      ContainerComponentTypeCodeSequence      1       DICOM
 (3004,0070)    DS      DVHMinimumDose  1       DICOM
 (3004,0072)    DS      DVHMaximumDose  1       DICOM
 (3004,0074)    DS      DVHMeanDose     1       DICOM
+(3004,0080)    SQ      DoseCalculationModelSequence    1       DICOM
+(3004,0081)    SQ      DoseCalculationAlgorithmSequence        1       DICOM
+(3004,0082)    CS      CommissioningStatus     1       DICOM
+(3004,0083)    SQ      DoseCalculationModelParameterSequence   1       DICOM
+(3004,0084)    CS      DoseDepositionCalculationMedium 1       DICOM
 (3006,0002)    SH      StructureSetLabel       1       DICOM
 (3006,0004)    LO      StructureSetName        1       DICOM
 (3006,0006)    ST      StructureSetDescription 1       DICOM
 (300A,0398)    FL      ScanningSpotSize        2       DICOM
 (300A,0399)    FL      ScanSpotSizesDelivered  2-2n    DICOM
 (300A,039A)    IS      NumberOfPaintings       1       DICOM
+(300A,039B)    FL      ScanSpotGantryAngles    1-n     DICOM
+(300A,039C)    FL      ScanSpotPatientSupportAngles    1-n     DICOM
 (300A,03A0)    SQ      IonToleranceTableSequence       1       DICOM
 (300A,03A2)    SQ      IonBeamSequence 1       DICOM
 (300A,03A4)    SQ      IonBeamLimitingDeviceSequence   1       DICOM
 (0010,1000)    LO      RETIRED_OtherPatientIDs 1-n     DICOM/retired
 (0010,1050)    LO      RETIRED_InsurancePlanIdentification     1-n     DICOM/retired
 (0010,1090)    LO      RETIRED_MedicalRecordLocator    1       DICOM/retired
+(0010,2160)    SH      RETIRED_EthnicGroup     1       DICOM/retired
 (0014,0023)    ST      RETIRED_CADFileFormat   1       DICOM/retired
 (0014,0024)    ST      RETIRED_ComponentReferenceSystem        1       DICOM/retired
 (0014,0045)    ST      RETIRED_MaterialPropertiesFileFormatRetired     1       DICOM/retired
 (7F00-7FFF,0020)       OW      RETIRED_VariableCoefficientsSDVN        1       DICOM/retired
 (7F00-7FFF,0030)       OW      RETIRED_VariableCoefficientsSDHN        1       DICOM/retired
 (7F00-7FFF,0040)       OW      RETIRED_VariableCoefficientsSDDN        1       DICOM/retired
-(7F00-7FFF,0040)       OW      RETIRED_VariableCoefficientsSDDN        1       DICOM/retired
 #
 #---------------------------------------------------------------------------
 #
index 799dda19fe62c71ebffe4c918071e7dcb7fd79b8..074bbc60d50fd02bbb8bd1919175968c7fdc0760 100644 (file)
@@ -14,269 +14,15 @@ cda2dcm [options] cdafile-in dcmfile-out
 
 \section cda2dcm_description DESCRIPTION
 
-The \b cda2dcm utility reads a CDA file (\e cdafile-in), converts it to a
-DICOM Encapsulated CDA Storage SOP instance and stores the converted data
-to an output file (\e dcmfile-out).
+The \b cda2dcm tool is deprecated.  Use \b dcmencap instead, which supports
+the same command line parameters, and more.
 
-\section cda2dcm_parameters PARAMETERS
+\section cda2dcm_see_also SEE ALSO
 
-\verbatim
-cdafile-in   CDA input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-\endverbatim
-
-\section cda2dcm_options OPTIONS
-
-\subsection cda2dcm_general_options general options
-\verbatim
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-\endverbatim
-
-\subsection cda2dcm_dicom_document_options DICOM document options
-\verbatim
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-
-override CDA file data:
-
-  -ov  --no-override
-         CDA patient and document data must match study,
-         series or manually entered information (default)
-
-  +ov  --override
-         data obtained from the CDA file will be overwritten
-         by study, series, or manually entered information
-\endverbatim
-
-\subsection cda2dcm_processing_options processing options
-\verbatim
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-\endverbatim
-
-\subsection cda2dcm_output_options output options
-\verbatim
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-\endverbatim
-
-\section cda2dcm_notes NOTES
-
-\subsection cda2dcm_attribute_sources Attribute Sources
-
-The application may be fed with some additional input for filling mandatory (and
-optional) attributes in the new DICOM file like patient, study and series
-information:
-
-- The \e --key option can be used to add further attributes to the DICOM output
-  file.
-
-- It is also possible to specify sequences, items and nested attributes using
-  the \e --key option. In these cases, a special "path" notation has to be
-  used.  Details on this path notation can be found in the documentation of
-  \b dcmodify.
-
-- The \e --key option can be present more than once.
-
-- The value part (after the '=') may be absent causing the attribute to be set
-  with zero length.
-
-- Please be advised that the \e --key option is applied at the very end, just
-  before saving the DICOM file, so there is no value checking whatsoever.
-
-\section cda2dcm_logging LOGGING
-
-The level of logging output of the various command line tools and underlying
-libraries can be specified by the user.  By default, only errors and warnings
-are written to the standard error stream.  Using option \e --verbose also
-informational messages like processing details are reported.  Option
-\e --debug can be used to get more details on the internal activity, e.g. for
-debugging purposes.  Other logging levels can be selected using option
-\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
-very severe error events, the application will usually terminate.  For more
-details on the different logging levels, see documentation of module "oflog".
-
-In case the logging output should be written to file (optionally with logfile
-rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
-can be used.  This configuration file also allows for directing only certain
-messages to a particular output stream and for filtering certain messages
-based on the module or application where they are generated.  An example
-configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
-
-\section cda2dcm_command_line COMMAND LINE
-
-All command line tools use the following notation for parameters: square
-brackets enclose optional values (0-1), three trailing dots indicate that
-multiple values are allowed (1-n), a combination of both means 0 to n values.
-
-Command line options are distinguished from parameters by a leading '+' or '-'
-sign, respectively.  Usually, order and position of command line options are
-arbitrary (i.e. they can appear anywhere).  However, if options are mutually
-exclusive the rightmost appearance is used.  This behavior conforms to the
-standard evaluation rules of common Unix shells.
-
-In addition, one or more command files can be specified using an '@' sign as a
-prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
-is replaced by the content of the corresponding text file (multiple
-whitespaces are treated as a single separator unless they appear between two
-quotation marks) prior to any further evaluation.  Please note that a command
-file cannot contain another command file.  This simple but effective approach
-allows one to summarize common combinations of options/parameters and avoids
-longish and confusing command lines (an example is provided in file
-<em>\<datadir\>/dumppat.txt</em>).
-
-\section cda2dcm_exit_codes EXIT CODES
-
-The \b cda2dcm utility uses the following exit codes when terminating.  This
-enables the user to check for the reason why the application terminated.
-
-\subsection cda2dcm_exit_codes_general general
-\verbatim
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-\endverbatim
-
-\subsection cda2dcm_exit_codes_input_file_errors input file errors
-\verbatim
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-\endverbatim
-
-\subsection cda2dcm_exit_codes_output_file_errors output file errors
-\verbatim
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-\endverbatim
-
-\section cda2dcm_environment ENVIRONMENT
-
-The \b cda2dcm utility will attempt to load DICOM data dictionaries specified
-in the \e DCMDICTPATH environment variable.  By default, i.e. if the
-\e DCMDICTPATH environment variable is not set, the file
-<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
-into the application (default for Windows).
-
-The default behavior should be preferred and the \e DCMDICTPATH environment
-variable only used when alternative data dictionaries are required.  The
-\e DCMDICTPATH environment variable has the same format as the Unix shell
-\e PATH variable in that a colon (":") separates entries.  On Windows systems,
-a semicolon (";") is used as a separator.  The data dictionary code will
-attempt to load each file specified in the \e DCMDICTPATH environment
-variable.
-It is an error if no data dictionary can be loaded.
+<b>dcmencap</b>(1)
 
 \section cda2dcm_copyright COPYRIGHT
 
-Copyright (C) 2018-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2018-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7262d920adee16ee068fd8138e59bab1d4d6cbd6..1a6cfcc7471f36f1792d6b1d77124878f4f355fa 100644 (file)
@@ -14,206 +14,15 @@ dcm2cda [options] dcmfile-in cdafile-out
 
 \section dcm2cda_description DESCRIPTION
 
-The \b dcm2cda utility reads a DICOM file of the Encapsulated CDA Storage SOP
-Class (\e dcmfile-in), extracts the embedded CDA document and writes it to an
-output file (\e cdafile-out).  Optionally a command can be executed after the
-creation of the CDA file.
-
-\section dcm2cda_parameters PARAMETERS
-
-\verbatim
-dcmfile-in   DICOM input filename ("-" for stdin)
-
-cdafile-out  CDA output filename
-\endverbatim
-
-\section dcm2cda_options OPTIONS
-
-\subsection dcm2cda_general_options general options
-\verbatim
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-\endverbatim
-
-\subsection dcm2cda_input_options input options
-\verbatim
-input file format:
-
-  +f   --read-file
-         read file format or data set (default)
-
-  +fo  --read-file-only
-         read file format only
-
-  -f   --read-dataset
-         read data set without file meta information
-
-input transfer syntax:
-
-  -t=  --read-xfer-auto
-         use TS recognition (default)
-
-  -td  --read-xfer-detect
-         ignore TS specified in the file meta header
-
-  -te  --read-xfer-little
-         read with explicit VR little endian TS
-
-  -tb  --read-xfer-big
-         read with explicit VR big endian TS
-
-  -ti  --read-xfer-implicit
-         read with implicit VR little endian TS
-
-parsing of odd-length attributes:
-
-  +ao  --accept-odd-length
-         accept odd length attributes (default)
-
-  +ae  --assume-even-length
-         assume real length is one byte larger
-
-handling of undefined length UN elements:
-
-  +ui  --enable-cp246
-         read undefined len UN as implicit VR (default)
-
-  -ui  --disable-cp246
-         read undefined len UN as explicit VR
-
-handling of defined length UN elements:
-
-  -uc  --retain-un
-         retain elements as UN (default)
-
-  +uc  --convert-un
-         convert to real VR if known
-
-automatic data correction:
-
-  +dc  --enable-correction
-         enable automatic data correction (default)
-
-  -dc  --disable-correction
-         disable automatic data correction
-
-bitstream format of deflated input:
-
-  +bd  --bitstream-deflated
-         expect deflated bitstream (default)
-
-  +bz  --bitstream-zlib
-         expect deflated zlib bitstream
-\endverbatim
-
-\section dcm2cda_logging LOGGING
-
-The level of logging output of the various command line tools and underlying
-libraries can be specified by the user.  By default, only errors and warnings
-are written to the standard error stream.  Using option \e --verbose also
-informational messages like processing details are reported.  Option
-\e --debug can be used to get more details on the internal activity, e.g. for
-debugging purposes.  Other logging levels can be selected using option
-\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
-very severe error events, the application will usually terminate.  For more
-details on the different logging levels, see documentation of module "oflog".
-
-In case the logging output should be written to file (optionally with logfile
-rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
-can be used.  This configuration file also allows for directing only certain
-messages to a particular output stream and for filtering certain messages
-based on the module or application where they are generated.  An example
-configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
-
-\section dcm2cda_exit_codes EXIT CODES
-
-The \b dcm2cda utility uses the following exit codes when terminating.  This
-enables the user to check for the reason why the application terminated.
-
-\subsection dcm2cda_exit_codes_general general
-\verbatim
-EXITCODE_NO_ERROR                         0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
-\endverbatim
-
-\subsection dcm2cda_exit_codes_input_file_errors input file errors
-\verbatim
-EXITCODE_CANNOT_READ_INPUT_FILE          20
-EXITCODE_NO_INPUT_FILES                  21
-EXITCODE_INVALID_INPUT_FILE              22
-\endverbatim
-
-\subsection dcm2cda_exit_codes_output_file_errors output file errors
-\verbatim
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
-\endverbatim
-
-\section dcm2cda_command_line COMMAND LINE
-
-All command line tools use the following notation for parameters: square
-brackets enclose optional values (0-1), three trailing dots indicate that
-multiple values are allowed (1-n), a combination of both means 0 to n values.
-
-Command line options are distinguished from parameters by a leading '+' or '-'
-sign, respectively.  Usually, order and position of command line options are
-arbitrary (i.e. they can appear anywhere).  However, if options are mutually
-exclusive the rightmost appearance is used.  This behavior conforms to the
-standard evaluation rules of common Unix shells.
-
-In addition, one or more command files can be specified using an '@' sign as a
-prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
-is replaced by the content of the corresponding text file (multiple
-whitespaces are treated as a single separator unless they appear between two
-quotation marks) prior to any further evaluation.  Please note that a command
-file cannot contain another command file.  This simple but effective approach
-allows one to summarize common combinations of options/parameters and avoids
-longish and confusing command lines (an example is provided in file
-<em>\<datadir\>/dumppat.txt</em>).
-
-\section dcm2cda_environment ENVIRONMENT
-
-The \b dcm2cda utility will attempt to load DICOM data dictionaries specified
-in the \e DCMDICTPATH environment variable.  By default, i.e. if the
-\e DCMDICTPATH environment variable is not set, the file
-<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
-into the application (default for Windows).
-
-The default behavior should be preferred and the \e DCMDICTPATH environment
-variable only used when alternative data dictionaries are required.  The
-\e DCMDICTPATH environment variable has the same format as the Unix shell
-\e PATH variable in that a colon (":") separates entries.  On Windows systems,
-a semicolon (";") is used as a separator.  The data dictionary code will
-attempt to load each file specified in the \e DCMDICTPATH environment variable.
-It is an error if no data dictionary can be loaded.
+The \b dcm2cda tool is deprecated.  Use \b dcmdecap instead, which supports
+the same command line parameters, and more.
 
 \section dcm2cda_see_also SEE ALSO
 
-<b>cda2dcm</b>(1)
+<b>dcmdecap</b>(1)
 
 \section dcm2cda_copyright COPYRIGHT
 
-Copyright (C) 2023-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2023-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 6d9c11ad42af85d4151069da608f9cf3b58c0de4..bcca01f8c299818d86eb8ab0e48407312227ef4f 100644 (file)
@@ -115,6 +115,27 @@ encoding of IS and DS (integer/decimal string) elements:
 
   -is  --is-ds-string
          always encode as string
+
+bulk data URI options:
+
+  -b   --bulk-disabled
+         write everything as inline binary (default)
+
+  +b   --bulk-enabled
+         write large attributes as bulk data
+
+  +bz  --bulk-size  [s]ize: integer (default: 1)
+         use bulk data for attributes >= s kBytes
+
+  +bp  --bulk-uri-prefix  [u]ri prefix: string
+         use prefix u when generating bulk data URIs (default: file URI)
+
+  +bd  --bulk-dir  [d]irectory: string
+         write bulk data files to d (default: '.')
+
+  +bs  --bulk-subdir
+         create subdirectory for each SOP instance
+         (default: no subdirectory)
 \endverbatim
 
 \subsection dcm2json_output_options output options
@@ -298,12 +319,50 @@ the following (see DICOM Part 18 Section F for details):
 
 \subsection dcm2json_bulk_data Bulk Data
 
-Binary data, i.e. DICOM element values with Value Representations (VR) of OB
-or OW, as well as OD, OF, OL, OV and UN values are always written as
-"InlineBinary" (base64 encoding) to the JSON output.  A future version of this
-tool might optionally use a "BulkDataURI" instead, i.e. the WADO-RS URL of a
-bulk data item that contains the element value.  This would be particularly
-useful for large amounts of data, such as pixel data.
+By default, binary data, i.e. DICOM element values with Value Representations
+(VR) of OB, OD, OF, OL, OV, OW, and UN values are written as "InlineBinary"
+(base64 encoding) to the JSON output.  Option \e --bulk-enabled causes binary
+data as well as DS, FD, FL, IS, SV and UV to be replaced by "BulkDataURI"
+values if the element value is larger than the cut-off threshold (default: 1
+kByte).  The cut-off threshold can be specified with the \e --bulk-size option.
+The element values themselves are written as files to the directory given by
+the \e --bulk-dir option (default: current directory).  The filename is based
+on a SHA-256 checksum of the element value.  By default, file URIs are
+generated that point to the bulk directory.  For production use, a URI prefix
+for a WADO-RS service over which the element values can be retrieved should be
+specified using the \e --bulk-uri-prefix option.  This can be implemented by
+configuring a web server that has read access to \b dcm2json's bulk directory.
+Finally, the option \e --bulk-subdir will cause a separate subdirectory to be
+created (and used in the bulk data URI) for each distinct SOP instance.
+
+Note that the JSON syntax for the representation of encapsulated pixel data
+in "InlineBinary" form is unspecified in DICOM, as is the JSON representation
+of encapsulated multi-frame pixel data.  These DICOM files cannot be converted
+to JSON using \b dcm2json.
+
+The file name extension for the bulk data files generated can be used to
+determine the MIME type that should be returned by the WADO-RS server:
+
+\verbatim
+  Extension     MIME Type
+
+  .bin          application/octet-stream
+  .jpeg         image/jpeg
+  .dicom-rle    image/dicom-rle
+  .jls          image/jls
+  .jp2          image/jp2
+  .jpx          image/jpx
+  .jphc         image/jphc
+  .jxl          image/jxl
+  .mpeg         video/mpeg
+  .mp4          video/mp4
+  .H265         video/H265
+\endverbatim
+
+Finally, it should be noted that bulk data will be written "as is", i.e.
+\b dcm2json will not attempt to validate or modify the element value in any
+way.  For example, \b dcm2json will not add a JFIF header in the case of JPEG
+baseline compressed images, which some JPEG viewers may expect.
 
 \section dcm2json_notes NOTES
 
@@ -322,8 +381,8 @@ parsers cannot process larger numbers.
 \subsection dcm2json_character_encoding Character Encoding
 
 As required by the DICOM JSON encoding, \b dcm2json always creates output in
-Unicode UTF-8 encoding and converts DICOM datasets accordingly.  If this is not
-possible, for example because DCMTK has been compiled without character set
+Unicode UTF-8 encoding and converts DICOM data sets accordingly.  If this is
+not possible, for example because DCMTK has been compiled without character set
 conversion support, an error is returned.
 
 \section dcm2json_logging LOGGING
@@ -423,6 +482,6 @@ replace any built-in tables.
 
 \section dcm2json_copyright COPYRIGHT
 
-Copyright (C) 2016-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2016-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index b0403771f6ba743aa7200370b0dbb2eacc64a0a0..d7aac94978b1d68b5ea04e12def8773aeac45825 100644 (file)
@@ -14,228 +14,15 @@ dcm2pdf [options] dcmfile-in pdffile-out
 
 \section dcm2pdf_description DESCRIPTION
 
-The \b dcm2pdf utility reads a DICOM file of the Encapsulated PDF Storage SOP
-Class (\e dcmfile-in), extracts the embedded PDF document and writes it to an
-output file (\e pdffile-out).  Optionally a command can be executed after the
-creation of the PDF file.
-
-\section dcm2pdf_parameters PARAMETERS
-
-\verbatim
-dcmfile-in   DICOM input filename ("-" for stdin)
-
-pdffile-out  PDF output filename
-\endverbatim
-
-\section dcm2pdf_options OPTIONS
-
-\subsection dcm2pdf_general_options general options
-\verbatim
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-\endverbatim
-
-\subsection dcm2pdf_input_options input options
-\verbatim
-input file format:
-
-  +f   --read-file
-         read file format or data set (default)
-
-  +fo  --read-file-only
-         read file format only
-
-  -f   --read-dataset
-         read data set without file meta information
-
-input transfer syntax:
-
-  -t=  --read-xfer-auto
-         use TS recognition (default)
-
-  -td  --read-xfer-detect
-         ignore TS specified in the file meta header
-
-  -te  --read-xfer-little
-         read with explicit VR little endian TS
-
-  -tb  --read-xfer-big
-         read with explicit VR big endian TS
-
-  -ti  --read-xfer-implicit
-         read with implicit VR little endian TS
-
-parsing of odd-length attributes:
-
-  +ao  --accept-odd-length
-         accept odd length attributes (default)
-
-  +ae  --assume-even-length
-         assume real length is one byte larger
-
-handling of undefined length UN elements:
-
-  +ui  --enable-cp246
-         read undefined len UN as implicit VR (default)
-
-  -ui  --disable-cp246
-         read undefined len UN as explicit VR
-
-handling of defined length UN elements:
-
-  -uc  --retain-un
-         retain elements as UN (default)
-
-  +uc  --convert-un
-         convert to real VR if known
-
-automatic data correction:
-
-  +dc  --enable-correction
-         enable automatic data correction (default)
-
-  -dc  --disable-correction
-         disable automatic data correction
-
-bitstream format of deflated input:
-
-  +bd  --bitstream-deflated
-         expect deflated bitstream (default)
-
-  +bz  --bitstream-zlib
-         expect deflated zlib bitstream
-\endverbatim
-
-\subsection dcm2pdf_processing_options processing options
-execution options:
-\verbatim
-  -x   --exec  [c]ommand: string
-         execute command c after PDF extraction
-\endverbatim
-
-\section dcm2pdf_notes NOTES
-
-Option \e --exec allows for the execution of a certain command line after the
-creation of the PDF document.  The command line to be executed is passed to
-this option as a parameter.  The specified command line may contain the
-placeholder '\#f', which will be replaced by the PDF filename at run time.
-The specified command line is executed in the foreground, i.e. \b pdf2dcm will
-be blocked until the command terminates.
-
-\section dcm2pdf_logging LOGGING
-
-The level of logging output of the various command line tools and underlying
-libraries can be specified by the user.  By default, only errors and warnings
-are written to the standard error stream.  Using option \e --verbose also
-informational messages like processing details are reported.  Option
-\e --debug can be used to get more details on the internal activity, e.g. for
-debugging purposes.  Other logging levels can be selected using option
-\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
-very severe error events, the application will usually terminate.  For more
-details on the different logging levels, see documentation of module "oflog".
-
-In case the logging output should be written to file (optionally with logfile
-rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
-can be used.  This configuration file also allows for directing only certain
-messages to a particular output stream and for filtering certain messages
-based on the module or application where they are generated.  An example
-configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
-
-\section dcm2pdf_exit_codes EXIT CODES
-
-The \b dcm2pdf utility uses the following exit codes when terminating.  This
-enables the user to check for the reason why the application terminated.
-
-\subsection dcm2cda_exit_codes_general general
-\verbatim
-EXITCODE_NO_ERROR                         0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
-\endverbatim
-
-\subsection dcm2cda_exit_codes_input_file_errors input file errors
-\verbatim
-EXITCODE_CANNOT_READ_INPUT_FILE          20
-EXITCODE_NO_INPUT_FILES                  21
-EXITCODE_INVALID_INPUT_FILE              22
-\endverbatim
-
-\subsection dcm2cda_exit_codes_output_file_errors output file errors
-\verbatim
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
-\endverbatim
-
-\subsection dcm2cda_exit_codes_processing_errors processing errors
-\verbatim
-EXITCODE_CANNOT_CONVERT_TO_UNICODE       80
-EXITCODE_CANNOT_WRITE_VALID_JSON         81
-\endverbatim
-
-\section dcm2pdf_command_line COMMAND LINE
-
-All command line tools use the following notation for parameters: square
-brackets enclose optional values (0-1), three trailing dots indicate that
-multiple values are allowed (1-n), a combination of both means 0 to n values.
-
-Command line options are distinguished from parameters by a leading '+' or '-'
-sign, respectively.  Usually, order and position of command line options are
-arbitrary (i.e. they can appear anywhere).  However, if options are mutually
-exclusive the rightmost appearance is used.  This behavior conforms to the
-standard evaluation rules of common Unix shells.
-
-In addition, one or more command files can be specified using an '@' sign as a
-prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
-is replaced by the content of the corresponding text file (multiple
-whitespaces are treated as a single separator unless they appear between two
-quotation marks) prior to any further evaluation.  Please note that a command
-file cannot contain another command file.  This simple but effective approach
-allows one to summarize common combinations of options/parameters and avoids
-longish and confusing command lines (an example is provided in file
-<em>\<datadir\>/dumppat.txt</em>).
-
-\section dcm2pdf_environment ENVIRONMENT
-
-The \b dcm2pdf utility will attempt to load DICOM data dictionaries specified
-in the \e DCMDICTPATH environment variable.  By default, i.e. if the
-\e DCMDICTPATH environment variable is not set, the file
-<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
-into the application (default for Windows).
-
-The default behavior should be preferred and the \e DCMDICTPATH environment
-variable only used when alternative data dictionaries are required.  The
-\e DCMDICTPATH environment variable has the same format as the Unix shell
-\e PATH variable in that a colon (":") separates entries.  On Windows systems,
-a semicolon (";") is used as a separator.  The data dictionary code will
-attempt to load each file specified in the \e DCMDICTPATH environment variable.
-It is an error if no data dictionary can be loaded.
+The \b dcm2pdf tool is deprecated.  Use \b dcmdecap instead, which supports
+the same command line parameters, and more.
 
 \section dcm2pdf_see_also SEE ALSO
 
-<b>pdf2dcm</b>(1)
+<b>dcmdecap</b>(1)
 
 \section dcm2pdf_copyright COPYRIGHT
 
-Copyright (C) 2007-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2007-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index a415951d4683e872c17532f997fe1c719f0757ef..ef776b1f3ea448c5ef824037995c2742d221a568 100644 (file)
@@ -405,6 +405,6 @@ replace any built-in tables.
 
 \section dcm2xml_copyright COPYRIGHT
 
-Copyright (C) 2002-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2002-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index e6d5ea603c04b30644bbf2f7c251757915163355..87fdd7b4a7d97919ad87594ffbab893809bfca67 100644 (file)
@@ -397,6 +397,6 @@ replace any built-in tables.
 
 \section dcmconv_copyright COPYRIGHT
 
-Copyright (C) 1994-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1994-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index f35402f823a613038dd0376e2f91594d336aeab6..4024ff71d35cd2e73c2e67de26c1efe6367d456a 100644 (file)
@@ -258,6 +258,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmcrle_copyright COPYRIGHT
 
-Copyright (C) 2002-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2002-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index ab99717c925c8cc11ae88a5bfa05695620a5e8b8..5bc8a5a4be10e859422f836143783dbb9be23bfd 100644 (file)
@@ -26,13 +26,16 @@ This module contains the following command line tools:
 \li \ref dcm2xml
 \li \ref dcmconv
 \li \ref dcmcrle
+\li \ref dcmdecap
 \li \ref dcmdrle
 \li \ref dcmdump
+\li \ref dcmencap
 \li \ref dcmftest
 \li \ref dcmgpdir
 \li \ref dcmodify
 \li \ref dump2dcm
 \li \ref img2dcm
+\li \ref json2dcm
 \li \ref pdf2dcm
 \li \ref stl2dcm
 \li \ref xml2dcm
diff --git a/dcmdata/docs/dcmdecap.man b/dcmdata/docs/dcmdecap.man
new file mode 100644 (file)
index 0000000..cbfbc9a
--- /dev/null
@@ -0,0 +1,240 @@
+/*!
+
+\if MANPAGES
+\page dcmdecap Extract encapsulated file from DICOM encapsulated storage object
+\else
+\page dcmdecap dcmdecap: Extract encapsulated file from DICOM encapsulated storage object
+\endif
+
+\section dcmdecap_synopsis SYNOPSIS
+
+\verbatim
+dcmdecap [options] dcmfile-in encfile-out
+\endverbatim
+
+\section dcmdecap_description DESCRIPTION
+
+The \b dcmdecap utility reads a DICOM file of one of the Encapsulated Storage SOP
+Classes (\e dcmfile-in), extracts the embedded document and writes it to an
+output file (\e encfile-out).  Optionally a command can be executed after the
+creation of the output file.
+
+\section dcmdecap_parameters PARAMETERS
+
+\verbatim
+dcmfile-in   DICOM input filename ("-" for stdin)
+
+encfile-out  Encapsulated document output filename ("-" for stdout)
+\endverbatim
+
+\section dcmdecap_options OPTIONS
+
+\subsection dcmdecap_general_options general options
+\verbatim
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+\endverbatim
+
+\subsection dcmdecap_input_options input options
+\verbatim
+input file format:
+
+  +f   --read-file
+         read file format or data set (default)
+
+  +fo  --read-file-only
+         read file format only
+
+  -f   --read-dataset
+         read data set without file meta information
+
+input transfer syntax:
+
+  -t=  --read-xfer-auto
+         use TS recognition (default)
+
+  -td  --read-xfer-detect
+         ignore TS specified in the file meta header
+
+  -te  --read-xfer-little
+         read with explicit VR little endian TS
+
+  -tb  --read-xfer-big
+         read with explicit VR big endian TS
+
+  -ti  --read-xfer-implicit
+         read with implicit VR little endian TS
+
+parsing of odd-length attributes:
+
+  +ao  --accept-odd-length
+         accept odd length attributes (default)
+
+  +ae  --assume-even-length
+         assume real length is one byte larger
+
+handling of undefined length UN elements:
+
+  +ui  --enable-cp246
+         read undefined len UN as implicit VR (default)
+
+  -ui  --disable-cp246
+         read undefined len UN as explicit VR
+
+handling of defined length UN elements:
+
+  -uc  --retain-un
+         retain elements as UN (default)
+
+  +uc  --convert-un
+         convert to real VR if known
+
+automatic data correction:
+
+  +dc  --enable-correction
+         enable automatic data correction (default)
+
+  -dc  --disable-correction
+         disable automatic data correction
+
+bitstream format of deflated input:
+
+  +bd  --bitstream-deflated
+         expect deflated bitstream (default)
+
+  +bz  --bitstream-zlib
+         expect deflated zlib bitstream
+\endverbatim
+
+\subsection dcmdecap_processing_options processing options
+execution options:
+\verbatim
+  -x   --exec  [c]ommand: string
+         execute command c after document extraction
+\endverbatim
+
+\section dcmdecap_notes NOTES
+
+Option \e --exec allows for the execution of a certain command line after the
+creation of the PDF document.  The command line to be executed is passed to
+this option as a parameter.  The specified command line may contain the
+placeholder '\#f', which will be replaced by the output filename at run time.
+The specified command line is executed in the foreground, i.e. \b dcmdecap will
+be blocked until the command terminates.
+
+\section dcmdecap_logging LOGGING
+
+The level of logging output of the various command line tools and underlying
+libraries can be specified by the user.  By default, only errors and warnings
+are written to the standard error stream.  Using option \e --verbose also
+informational messages like processing details are reported.  Option
+\e --debug can be used to get more details on the internal activity, e.g. for
+debugging purposes.  Other logging levels can be selected using option
+\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
+very severe error events, the application will usually terminate.  For more
+details on the different logging levels, see documentation of module "oflog".
+
+In case the logging output should be written to file (optionally with logfile
+rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
+can be used.  This configuration file also allows for directing only certain
+messages to a particular output stream and for filtering certain messages
+based on the module or application where they are generated.  An example
+configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
+
+\section dcmdecap_exit_codes EXIT CODES
+
+The \b dcmdecap utility uses the following exit codes when terminating.  This
+enables the user to check for the reason why the application terminated.
+
+\subsection dcmdecap_exit_codes_general general
+\verbatim
+EXITCODE_NO_ERROR                         0
+EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
+\endverbatim
+
+\subsection dcmdecap_exit_codes_input_file_errors input file errors
+\verbatim
+EXITCODE_CANNOT_READ_INPUT_FILE          20
+EXITCODE_NO_INPUT_FILES                  21
+EXITCODE_INVALID_INPUT_FILE              22
+\endverbatim
+
+\subsection dcmdecap_exit_codes_output_file_errors output file errors
+\verbatim
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
+\endverbatim
+
+\subsection dcmdecap_exit_codes_processing_errors processing errors
+\verbatim
+EXITCODE_EXEC_FAILED                     91
+\endverbatim
+
+\section dcmdecap_command_line COMMAND LINE
+
+All command line tools use the following notation for parameters: square
+brackets enclose optional values (0-1), three trailing dots indicate that
+multiple values are allowed (1-n), a combination of both means 0 to n values.
+
+Command line options are distinguished from parameters by a leading '+' or '-'
+sign, respectively.  Usually, order and position of command line options are
+arbitrary (i.e. they can appear anywhere).  However, if options are mutually
+exclusive the rightmost appearance is used.  This behavior conforms to the
+standard evaluation rules of common Unix shells.
+
+In addition, one or more command files can be specified using an '@' sign as a
+prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
+is replaced by the content of the corresponding text file (multiple
+whitespaces are treated as a single separator unless they appear between two
+quotation marks) prior to any further evaluation.  Please note that a command
+file cannot contain another command file.  This simple but effective approach
+allows one to summarize common combinations of options/parameters and avoids
+longish and confusing command lines (an example is provided in file
+<em>\<datadir\>/dumppat.txt</em>).
+
+\section dcmdecap_environment ENVIRONMENT
+
+The \b dcmdecap utility will attempt to load DICOM data dictionaries specified
+in the \e DCMDICTPATH environment variable.  By default, i.e. if the
+\e DCMDICTPATH environment variable is not set, the file
+<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
+into the application (default for Windows).
+
+The default behavior should be preferred and the \e DCMDICTPATH environment
+variable only used when alternative data dictionaries are required.  The
+\e DCMDICTPATH environment variable has the same format as the Unix shell
+\e PATH variable in that a colon (":") separates entries.  On Windows systems,
+a semicolon (";") is used as a separator.  The data dictionary code will
+attempt to load each file specified in the \e DCMDICTPATH environment variable.
+It is an error if no data dictionary can be loaded.
+
+\section dcmdecap_see_also SEE ALSO
+
+<b>dcmencap</b>(1)
+
+\section dcmdecap_copyright COPYRIGHT
+
+Copyright (C) 2007-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+
+*/
index 65f8cc9c4a42a9e069390a6810e6370ba7bd0b49..395886ee50374d9baeced6f7134f66096b5d171f 100644 (file)
@@ -247,6 +247,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmdrle_copyright COPYRIGHT
 
-Copyright (C) 2002-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany
+Copyright (C) 2002-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany
 
 */
index a1ee447c6a734037c9dfad69d72ad9aca52aa780..8edd7af584cf5169261b1da530f549865a17242f 100644 (file)
@@ -429,6 +429,6 @@ replace any built-in tables.
 
 \section dcmdump_copyright COPYRIGHT
 
-Copyright (C) 1994-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1994-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
diff --git a/dcmdata/docs/dcmencap.man b/dcmdata/docs/dcmencap.man
new file mode 100644 (file)
index 0000000..589aab1
--- /dev/null
@@ -0,0 +1,320 @@
+/*!
+
+\if MANPAGES
+\page dcmencap Encapsulate document into DICOM format
+\else
+\page dcmencap dcmencap: Encapsulate document into DICOM format
+\endif
+
+\section dcmencap_synopsis SYNOPSIS
+
+\verbatim
+dcmencap [options] docfile-in dcmfile-out
+\endverbatim
+
+\section dcmencap_description DESCRIPTION
+
+The \b dcmencap utility reads a document file in one of the supported file formats,
+converts it to a SOP instance of the corresponding DICOM Encapsulated Storage SOP Class
+and stores the converted data in an output file (\e dcmfile-out).
+
+\section dcmencap_parameters PARAMETERS
+
+\verbatim
+docfile-in   input filename to be converted
+
+dcmfile-out  DICOM output filename ("-" for stdout)
+\endverbatim
+
+\section dcmencap_options OPTIONS
+
+\subsection dcmencap_general_options general options
+\verbatim
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+\endverbatim
+
+\subsection dcmencap_input_options input options
+\verbatim
+input file format:
+
+  +fa  --filetype-auto
+         automatically determine file type (default)
+
+  +fp  --filetype-pdf
+         expect PDF file
+
+  +fc  --filetype-cda
+         expect CDA file
+
+  +fs  --filetype-stl
+         expect STL file
+
+  +fm  --filetype-mtl
+         expect MTL file
+
+  +fo  --filetype-obj
+         expect OBJ file
+\endverbatim
+
+\subsection dcmencap_dicom_document_options DICOM document options
+\verbatim
+document title:
+
+  +t   --title  [t]itle: string (default: empty)
+         document title
+
+  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
+         coded representation of document title defined by coding
+         scheme designator CSD, code value CV and code meaning CM
+
+patient data:
+
+  +pn  --patient-name  [n]ame: string
+         patient's name in DICOM PN syntax
+
+  +pi  --patient-id  [i]d: string
+         patient identifier
+
+  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
+         patient's birth date
+
+  +ps  --patient-sex  [s]ex: string (M, F or O)
+         patient's sex
+
+device data:
+
+  +mn  --manufacturer  [n]ame: string
+         manufacturer's name
+
+  +mm  --manufacturer-model  [n]ame: string
+         manufacturer's model name
+
+  +ds  --device-serial  [n]umber: string
+         device serial number
+
+  +sv  --software-versions  [v]ersions: string
+         software versions
+
+manufacturing 3d model data (STL/MTL/OBJ only):
+
+  +mu  --measurement-units  [CSD] [CV] [CM]: string
+         measurement units with coding scheme designator CSD,
+         code value CV and code meaning CM (default: UCUM, um, um)
+
+study and series:
+
+  +sg  --generate
+         generate new study and series UIDs (default)
+
+  +st  --study-from  [f]ilename: string
+         read patient/study data from DICOM file
+
+  +se  --series-from  [f]ilename: string
+         read patient/study/series data from DICOM file
+
+instance number:
+
+  +i1  --instance-one
+         use instance number 1 (default, not with +se)
+
+  +ii  --instance-inc
+         increment instance number (only with +se)
+
+  +is  --instance-set [i]nstance number: integer
+         use instance number i
+
+burned-in annotation:
+
+  +an  --annotation-yes
+         document contains patient identifying data (default)
+
+  -an  --annotation-no
+         document does not contain patient identifying data
+\endverbatim
+
+\subsection dcmencap_processing_options processing options
+\verbatim
+CDA processing options:
+
+  -ov  --no-override
+         CDA patient and document data must match study,
+         series or manually entered information (default)
+
+  +ov  --override
+         CDA's data will be overwritten by study, series
+         or manually entered information
+
+other processing options:
+
+  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
+         add further attribute
+\endverbatim
+
+\subsection dcmencap_output_options output options
+\verbatim
+output transfer syntax:
+  +te  --write-xfer-little
+         write with explicit VR little endian (default)
+
+  +tb  --write-xfer-big
+         write with explicit VR big endian TS
+
+  +ti  --write-xfer-implicit
+         write with implicit VR little endian TS
+
+group length encoding:
+
+  -g   --group-length-remove
+         write without group length elements (default)
+
+  +g   --group-length-create
+         write with group length elements
+
+length encoding in sequences and items:
+
+  +e   --length-explicit
+         write with explicit lengths (default)
+
+  -e   --length-undefined
+         write with undefined lengths
+
+data set trailing padding (not with --write-dataset):
+
+  -p   --padding-off
+         no padding (implicit if --write-dataset)
+
+  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
+         align file on multiple of f bytes
+         and items on multiple of i bytes
+\endverbatim
+
+\section dcmencap_notes NOTES
+
+\subsection dcmencap_attribute_sources Attribute Sources
+
+The application may be fed with some additional input for filling mandatory
+(and optional) attributes in the new DICOM file like patient, study and series
+information:
+
+- The \e --key option can be used to add further attributes to the DICOM output
+  file.
+
+- It is also possible to specify sequences, items and nested attributes using
+  the \e --key option. In these cases, a special "path" notation has to be
+  used.  Details on this path notation can be found in the documentation of
+  \b dcmodify.
+
+- The \e --key option can be present more than once.
+
+- The value part (after the '=') may be absent causing the attribute to be set
+  with zero length.
+
+- Please be advised that the \e --key option is applied at the very end, just
+  before saving the DICOM file, so there is no value checking whatsoever.
+
+\section dcmencap_logging LOGGING
+
+The level of logging output of the various command line tools and underlying
+libraries can be specified by the user.  By default, only errors and warnings
+are written to the standard error stream.  Using option \e --verbose also
+informational messages like processing details are reported.  Option
+\e --debug can be used to get more details on the internal activity, e.g. for
+debugging purposes.  Other logging levels can be selected using option
+\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
+very severe error events, the application will usually terminate.  For more
+details on the different logging levels, see documentation of module "oflog".
+
+In case the logging output should be written to file (optionally with logfile
+rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
+can be used.  This configuration file also allows for directing only certain
+messages to a particular output stream and for filtering certain messages
+based on the module or application where they are generated.  An example
+configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
+
+\section dcmencap_command_line COMMAND LINE
+
+All command line tools use the following notation for parameters: square
+brackets enclose optional values (0-1), three trailing dots indicate that
+multiple values are allowed (1-n), a combination of both means 0 to n values.
+
+Command line options are distinguished from parameters by a leading '+' or '-'
+sign, respectively.  Usually, order and position of command line options are
+arbitrary (i.e. they can appear anywhere).  However, if options are mutually
+exclusive the rightmost appearance is used.  This behavior conforms to the
+standard evaluation rules of common Unix shells.
+
+In addition, one or more command files can be specified using an '@' sign as a
+prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
+is replaced by the content of the corresponding text file (multiple
+whitespaces are treated as a single separator unless they appear between two
+quotation marks) prior to any further evaluation.  Please note that a command
+file cannot contain another command file.  This simple but effective approach
+allows one to summarize common combinations of options/parameters and avoids
+longish and confusing command lines (an example is provided in file
+<em>\<datadir\>/dumppat.txt</em>).
+
+\section dcmencap_exit_codes EXIT CODES
+
+The \b dcmencap utility uses the following exit codes when terminating.  This
+enables the user to check for the reason why the application terminated.
+
+\subsection dcmencap_exit_codes_general general
+\verbatim
+EXITCODE_NO_ERROR                 0
+\endverbatim
+
+\subsection dcmencap_exit_codes_input_file_errors input file errors
+\verbatim
+EXITCODE_INVALID_INPUT_FILE       22
+\endverbatim
+
+\subsection dcmencap_exit_codes_output_file_errors output file errors
+\verbatim
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
+\endverbatim
+
+\section dcmencap_environment ENVIRONMENT
+
+The \b dcmencap utility will attempt to load DICOM data dictionaries specified
+in the \e DCMDICTPATH environment variable.  By default, i.e. if the
+\e DCMDICTPATH environment variable is not set, the file
+<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
+into the application (default for Windows).
+
+The default behavior should be preferred and the \e DCMDICTPATH environment
+variable only used when alternative data dictionaries are required.  The
+\e DCMDICTPATH environment variable has the same format as the Unix shell
+\e PATH variable in that a colon (":") separates entries.  On Windows systems,
+a semicolon (";") is used as a separator.  The data dictionary code will
+attempt to load each file specified in the \e DCMDICTPATH environment
+variable.
+It is an error if no data dictionary can be loaded.
+
+\section dcmencap_copyright COPYRIGHT
+
+Copyright (C) 2018-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+
+*/
index 66231ced3c1feb7672a29ccd25f38642ee977c08..bae866484913994084a2e85d0f9f36e0cfe1ea6f 100644 (file)
@@ -39,6 +39,6 @@ is intended for use in shell script programming.
 
 \section dcmftest_copyright COPYRIGHT
 
-Copyright (C) 1997-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1997-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index ef262d7b81407b4b94fc143b0ec35bd590f63cee..e54708c0b207ff2a441b23a0d1d4fd4340d3f106 100644 (file)
@@ -23,6 +23,6 @@ the same command line parameters, and more.
 
 \section dcmgpdir_copyright COPYRIGHT
 
-Copyright (C) 1996-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1996-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 9f67068084c735dd6df7979f2cba1cdef59a7f2b..31a675733ceaac002984d757334fba48ecfe8f72 100644 (file)
@@ -589,6 +589,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmodify_copyright COPYRIGHT
 
-Copyright (C) 2003-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2003-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 22ebefbe936b31ff2718232c82e8f3d2e9c16c95..6c6049926926f76cb62984485d303578f6c4e6bf 100644 (file)
@@ -314,6 +314,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dump2dcm_copyright COPYRIGHT
 
-Copyright (C) 1996-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1996-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 316432e884d00369c56b176fdb421cd8813d7b9b..20cd08631779811a09b2773ee6ab5f5fe908b31b 100644 (file)
@@ -429,7 +429,7 @@ However, if you want to keep APPn markers (e.g. APP8/HP color transform
 information, aka 'mrfx') inside the DICOM stream, the option \e --keep-appn
 does the trick.  Pay attention that the plugin will check the actual color
 transform specified in the APP8/HP marker.  Since DICOM does not allow any
-color transform to be specified in the APP8 marker, only a value of `0` (no
+color transform to be specified in the APP8 marker, only a value of 0 (no
 color transform) is accepted.
 
 \subsubsection img2dcm_bmp_input_plugin BMP Input Plugin
@@ -581,6 +581,6 @@ Photography images
 
 \section img2dcm_copyright COPYRIGHT
 
-Copyright (C) 2007-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2007-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
diff --git a/dcmdata/docs/json2dcm.man b/dcmdata/docs/json2dcm.man
new file mode 100644 (file)
index 0000000..9091992
--- /dev/null
@@ -0,0 +1,481 @@
+/*!
+
+\if MANPAGES
+\page json2dcm Convert JSON document to DICOM file or data set
+\else
+\page json2dcm json2dcm: Convert JSON document to DICOM file or data set
+\endif
+
+\section json2dcm_synopsis SYNOPSIS
+
+\verbatim
+json2dcm [options] jsonfile-in dcmfile-out
+\endverbatim
+
+\section json2dcm_description DESCRIPTION
+
+The \b json2dcm utility converts the contents of a JSON (JavaScript Object
+Notation) document to a binary DICOM file or data set.  The JSON document is
+expected to conform to the "DICOM JSON Model" as defined in DICOM Part 18
+Section F.  Such JSON files can be created, e.g., using the \b dcm2json tool.
+
+\section json2dcm_parameters PARAMETERS
+
+\verbatim
+jsonfile-in  JSON input filename to be converted ("-" for stdin)
+
+dcmfile-out  DICOM output filename ("-" for stdout)
+\endverbatim
+
+\section json2dcm_options OPTIONS
+
+\subsection json2dcm_general_options general options
+\verbatim
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+\endverbatim
+
+\subsection json2dcm_input_options input options
+\verbatim
+input file format:
+
+  +f   --read-meta-info
+         read meta information if present (default)
+
+  -f   --ignore-meta-info
+         ignore file meta information
+\endverbatim
+
+\subsection json2dcm_processing_options processing options
+\verbatim
+unique identifiers:
+
+  +Ug  --generate-new-uids
+         generate new Study/Series/SOP Instance UID
+
+  -Uo  --dont-overwrite-uids
+         do not overwrite existing UIDs (default)
+
+  +Uo  --overwrite-uids
+         overwrite existing UIDs
+
+bulkdata URI handling:
+
+  +Bu  --parse-bulkdata-uri
+         parse Bulkdata URIs (default)
+
+  -Bu  --ignore-bulkdata-uri
+         ignore Bulkdata URIs
+
+  +Bd  --add-bulkdata-dir  [d]irectory: string
+         add d to list of permitted bulk data sources
+
+handling of arrays with multiple data sets:
+
+  -ar  --array-reject
+         reject multiple data sets (default)
+
+  +as  --array-select  [n]umber: integer
+         select data set n from array
+
+  +ar  --array-sequence
+         store all data sets in private sequence
+\endverbatim
+
+\subsection json2dcm_output_options output options
+\verbatim
+output file format:
+
+  +F   --write-file
+         write file format (default)
+
+  -F   --write-dataset
+         write data set without file meta information
+
+  +Fu  --update-meta-info
+         update particular file meta information
+
+output transfer syntax:
+
+  +t=  --write-xfer-same
+         write with same TS as input (default)
+
+  +te  --write-xfer-little
+         write with explicit VR little endian TS
+
+  +tb  --write-xfer-big
+         write with explicit VR big endian TS
+
+  +ti  --write-xfer-implicit
+         write with implicit VR little endian TS
+
+  +td  --write-xfer-deflated
+         write with deflated explicit VR little endian TS
+
+error handling:
+
+  -E   --stop-on-error
+         do not write if document is invalid (default)
+
+  +E   --ignore-errors
+         attempt to write even if document is invalid
+
+post-1993 value representations:
+
+  +u   --enable-new-vr
+         enable support for new VRs (UN/UT) (default)
+
+  -u   --disable-new-vr
+         disable support for new VRs, convert to OB
+
+length encoding in sequences and items:
+
+  +e   --length-explicit
+         write with explicit lengths (default)
+
+  -e   --length-undefined
+         write with undefined lengths
+
+charset handling:
+
+  +c   --charset-accept
+         write with the given charset in JSON (default)
+
+  -c   --charset-replace
+         replace the given charset in JSON with UTF-8
+
+deflate compression level (only with --write-xfer-deflated):
+
+  +cl  --compression-level  [l]evel: integer (default: 6)
+         0=uncompressed, 1=fastest, 9=best compression
+\endverbatim
+
+\section json2dcm_notes NOTES
+
+The basic structure of the JSON input expected looks like the following (see
+DICOM Part 18 Section F for details):
+
+\verbatim
+{
+    "00080005": {
+        "vr": "CS",
+        "Value": [
+            "ISO_IR 192"
+        ]
+    },
+    "00080020": {
+        "vr": "DT",
+        "Value": [
+            "20130409"
+        ]
+    },
+    "00080030": {
+        "vr": "TM",
+        "Value": [
+            "131600.0000"
+        ]
+    },
+    "00080050": {
+        "vr": "SH",
+        "Value": [
+            "11235813"
+        ]
+    },
+    "00080056": {
+        "vr": "CS",
+        "Value": [
+            "ONLINE"
+        ]
+    },
+    "00080061": {
+        "vr": "CS",
+        "Value": [
+            "CT",
+            "PET"
+        ]
+    },
+    "00080090": {
+        "vr": "PN",
+        "Value": [
+          {
+            "Alphabetic": "^Bob^^Dr."
+          }
+        ]
+    },
+    "00081190": {
+        "vr": "UR",
+        "Value": [
+            "http://wado.nema.org/studies/
+            1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
+        ]
+    },
+    "00090010": {
+        "vr": "LO",
+        "Value": [
+            "Vendor A"
+        ]
+    },
+    "00091002": {
+        "vr": "UN",
+        "InlineBinary": "z0x9c8v7"
+    },
+    "00100010": {
+        "vr": "PN",
+        "Value": [
+          {
+            "Alphabetic": "Wang^XiaoDong"
+          }
+        ]
+    },
+    "00100020": {
+        "vr": "LO",
+        "Value": [
+            "12345"
+        ]
+    },
+    "00100021": {
+        "vr": "LO",
+        "Value": [
+            "Hospital A"
+        ]
+    },
+    "00100030": {
+        "vr": "DA",
+        "Value": [
+            "19670701"
+        ]
+    },
+    "00100040": {
+        "vr": "CS",
+        "Value": [
+            "M"
+        ]
+    },
+    "00101002": {
+        "vr": "SQ",
+        "Value": [
+            {
+                "00100020": {
+                    "vr": "LO",
+                    "Value": [
+                        "54321"
+                    ]
+                },
+                "00100021": {
+                    "vr": "LO",
+                    "Value": [
+                        "Hospital B"
+                    ]
+                }
+            },
+            {
+                "00100020": {
+                    "vr": "LO",
+                    "Value": [
+                        "24680"
+                    ]
+                },
+                "00100021": {
+                    "vr": "LO",
+                    "Value": [
+                        "Hospital C"
+                    ]
+                }
+            }
+        ]
+    },
+    "0020000D": {
+        "vr": "UI",
+        "Value": [
+            "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
+        ]
+    },
+    "00200010": {
+        "vr": "SH",
+        "Value": [
+            "11235813"
+        ]
+    },
+    "00201206": {
+        "vr": "IS",
+        "Value": [
+            4
+        ]
+    },
+    "00201208": {
+        "vr": "IS",
+        "Value": [
+            942
+        ]
+    }
+}
+\endverbatim
+
+\subsection json2dcm_character_encoding Character Encoding
+
+The JSON format only supports UTF-8 encoding.  Thus the generated DICOM file
+will also contain UTF-8 encoding.  If the JSON file does not contain a specific
+character set, or a specific character set other than "ISO_IR 192", a warning
+will be issued.
+
+\subsection json2dcm_bulk_data Binary Data, Bulk Data, and Pixel Data
+
+The DICOM JSON Model uses "InlineBinary" to store attribute values of binary
+value representations such as "OB", "OW", "OD", "OF", "OL", "OV" etc.
+in Base64 encoded form.  This is supported in \b json2dcm for all binary
+attributes, including unencapsulated pixel data.
+
+The DICOM JSON Model also permits attribute values to be stored separately
+from the JSON data set and to be referenced through a BulkDataURI.
+This is supported for file URIs that reference files in the local filesystem.
+\b json2dcm tool also supports the inofficial extension to the file URI
+scheme generated by \e DCM4CHE, where parameters named "offset" and "length"
+are appended to the file URI in order to refer to a specific part of a file.
+HTTP URIs as well as URIs that identify another part in a MIME
+multipart/related structure are not yet supported in \b json2dcm.
+If the command line option \e --ignore-bulkdata-uri is specified,
+then all bulk data URIs are ignored and attributes with bulk data
+will be written with empty value.
+
+Finally, encapsulated (in particular, compressed) pixel data is not supported
+by \b json2dcm because the syntax of the DICOM JSON Model for this specific
+case is not defined in the DICOM standard yet.
+
+\subsection json2dcm_arrays Arrays of Data Sets
+
+The DICOM JSON Model uses a JSON array structure to return multiple data sets
+in DICOMweb services such as WADO-RS or QIDO-RS.  JSON arrays containing a
+single DICOM data set are automatically recognized by \b json2dcm and treated
+like a data set without the surrounding array structure.  JSON arrays
+containing multiple data sets are rejected by default.  Alternatively, the
+\e --array-select option can be used to select one data set from the array to
+be converted.  The \e --array-sequence option causes all data sets to be
+written as sequence items into a single private sequence with attribute tag
+(0009,1000).  Such files, which are mostly intended for debugging purposes, can
+be recognized by the private creator element (0009,0010), which has the value
+"JSON2DCM_LIST_OF_DATASETS".
+
+\subsection json2dcm_trailing_commas Trailing Commas
+
+Trailing commas are not permitted in JSON, but \b json2dcm will still accept
+such JSON data sets without warning or error message because they are handled
+gracefully by the underlying JSON parser.  Users should, therefore, not assume
+that a JSON data set is valid just because \b json2dcm accepts it.  This tool
+is not designed as a validator for JSON or the DICOM JSON Model.
+
+\section json2dcm_logging LOGGING
+
+The level of logging output of the various command line tools and underlying
+libraries can be specified by the user.  By default, only errors and warnings
+are written to the standard error stream.  Using option \e --verbose also
+informational messages like processing details are reported.  Option
+\e --debug can be used to get more details on the internal activity, e.g. for
+debugging purposes.  Other logging levels can be selected using option
+\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
+very severe error events, the application will usually terminate.  For more
+details on the different logging levels, see documentation of module "oflog".
+
+In case the logging output should be written to file (optionally with logfile
+rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
+can be used.  This configuration file also allows for directing only certain
+messages to a particular output stream and for filtering certain messages
+based on the module or application where they are generated.  An example
+configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
+
+\section json2dcm_command_line COMMAND LINE
+
+All command line tools use the following notation for parameters: square
+brackets enclose optional values (0-1), three trailing dots indicate that
+multiple values are allowed (1-n), a combination of both means 0 to n values.
+
+Command line options are distinguished from parameters by a leading '+' or '-'
+sign, respectively.  Usually, order and position of command line options are
+arbitrary (i.e. they can appear anywhere).  However, if options are mutually
+exclusive the rightmost appearance is used.  This behavior conforms to the
+standard evaluation rules of common Unix shells.
+
+In addition, one or more command files can be specified using an '@' sign as a
+prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
+is replaced by the content of the corresponding text file (multiple
+whitespaces are treated as a single separator unless they appear between two
+quotation marks) prior to any further evaluation.  Please note that a command
+file cannot contain another command file.  This simple but effective approach
+allows one to summarize common combinations of options/parameters and avoids
+longish and confusing command lines (an example is provided in file
+<em>\<datadir\>/dumppat.txt</em>).
+
+\section json2dcm_exit_codes EXIT CODES
+
+The \b dcm2json utility uses the following exit codes when terminating.  This
+enables the user to check for the reason why the application terminated.
+
+\subsection json2dcm_exit_codes_general general
+\verbatim
+EXITCODE_NO_ERROR                               0
+EXITCODE_COMMANDLINE_SYNTAX_ERROR               1
+\endverbatim
+
+\subsection json2dcm_exit_codes_input_file_errors input file errors
+\verbatim
+EXITCODE_CANNOT_READ_INPUT_FILE                 20
+\endverbatim
+
+\subsection json2dcm_exit_codes_output_file_errors output file errors
+\verbatim
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE               40
+\endverbatim
+
+\subsection json2dcm_exit_codes_processing_errors processing errors
+\verbatim
+EXITCODE_INVALID_JSON_CONTENT                   65
+EXITCODE_BULKDATA_URI_NOT_SUPPORTED             66
+\endverbatim
+
+\section json2dcm_environment ENVIRONMENT
+
+The \b json2dcm utility will attempt to load DICOM data dictionaries specified
+in the \e DCMDICTPATH environment variable.  By default, i.e. if the
+\e DCMDICTPATH environment variable is not set, the file
+<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
+into the application (default for Windows).
+
+The default behavior should be preferred and the \e DCMDICTPATH environment
+variable only used when alternative data dictionaries are required.  The
+\e DCMDICTPATH environment variable has the same format as the Unix shell
+\e PATH variable in that a colon (":") separates entries.  On Windows systems,
+a semicolon (";") is used as a separator.  The data dictionary code will
+attempt to load each file specified in the \e DCMDICTPATH environment variable.
+It is an error if no data dictionary can be loaded.
+
+\section json2dcm_see_also SEE ALSO
+
+<b>dcm2json</b>(1)
+<b>dump2dcm</b>(2)
+
+\section json2dcm_copyright COPYRIGHT
+
+Copyright (C) 2024-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+
+*/
index e923cef19eff842417de6c4aedf0eb627f7f310e..ff989c63ea4397c9b637d5bcb40ced42c307d536 100644 (file)
@@ -14,263 +14,15 @@ pdf2dcm [options] pdffile-in dcmfile-out
 
 \section pdf2dcm_description DESCRIPTION
 
-The \b pdf2dcm utility reads a PDF file (\e pdffile-in), converts it to a
-DICOM Encapsulated PDF Storage SOP instance and stores the converted data
-to an output file (\e dcmfile-out).
-
-\section pdf2dcm_parameters PARAMETERS
-
-\verbatim
-pdffile-in   PDF input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-\endverbatim
-
-\section pdf2dcm_options OPTIONS
-
-\subsection pdf2dcm_general_options general options
-\verbatim
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-\endverbatim
-
-\subsection pdf2dcm_dicom_document_options DICOM document options
-\verbatim
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-\endverbatim
-
-\subsection pdf2dcm_processing_options processing options
-\verbatim
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-\endverbatim
-
-\subsection pdf2dcm_output_options output options
-\verbatim
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-\endverbatim
-
-\section pdf2dcm_notes NOTES
-
-\subsection pdf2dcm_attribute_sources Attribute Sources
-
-The application may be fed with some additional input for filling mandatory
-(and optional) attributes in the new DICOM file like patient, study and series
-information:
-
-- The \e --key option can be used to add further attributes to the DICOM output
-  file.
-
-- It is also possible to specify sequences, items and nested attributes using
-  the \e --key option. In these cases, a special "path" notation has to be
-  used.  Details on this path notation can be found in the documentation of
-  \b dcmodify.
-
-- The \e --key option can be present more than once.
-
-- The value part (after the '=') may be absent causing the attribute to be set
-  with zero length.
-
-- Please be advised that the \e --key option is applied at the very end, just
-  before saving the DICOM file, so there is no value checking whatsoever.
-
-\section pdf2dcm_logging LOGGING
-
-The level of logging output of the various command line tools and underlying
-libraries can be specified by the user.  By default, only errors and warnings
-are written to the standard error stream.  Using option \e --verbose also
-informational messages like processing details are reported.  Option
-\e --debug can be used to get more details on the internal activity, e.g. for
-debugging purposes.  Other logging levels can be selected using option
-\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
-very severe error events, the application will usually terminate.  For more
-details on the different logging levels, see documentation of module "oflog".
-
-In case the logging output should be written to file (optionally with logfile
-rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
-can be used.  This configuration file also allows for directing only certain
-messages to a particular output stream and for filtering certain messages
-based on the module or application where they are generated.  An example
-configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
-
-\section pdf2dcm_command_line COMMAND LINE
-
-All command line tools use the following notation for parameters: square
-brackets enclose optional values (0-1), three trailing dots indicate that
-multiple values are allowed (1-n), a combination of both means 0 to n values.
-
-Command line options are distinguished from parameters by a leading '+' or '-'
-sign, respectively.  Usually, order and position of command line options are
-arbitrary (i.e. they can appear anywhere).  However, if options are mutually
-exclusive the rightmost appearance is used.  This behavior conforms to the
-standard evaluation rules of common Unix shells.
-
-In addition, one or more command files can be specified using an '@' sign as a
-prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
-is replaced by the content of the corresponding text file (multiple
-whitespaces are treated as a single separator unless they appear between two
-quotation marks) prior to any further evaluation.  Please note that a command
-file cannot contain another command file.  This simple but effective approach
-allows one to summarize common combinations of options/parameters and avoids
-longish and confusing command lines (an example is provided in file
-<em>\<datadir\>/dumppat.txt</em>).
-
-\section pdf2dcm_exit_codes EXIT CODES
-
-The \b pdf2dcm utility uses the following exit codes when terminating.  This
-enables the user to check for the reason why the application terminated.
-
-\subsection pdf2dcm_exit_codes_general general
-\verbatim
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-\endverbatim
-
-\subsection pdf2dcm_exit_codes_input_file_errors input file errors
-\verbatim
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-\endverbatim
-
-\subsection pdf2dcm_exit_codes_output_file_errors output file errors
-\verbatim
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-\endverbatim
-
-\section pdf2dcm_environment ENVIRONMENT
-
-The \b pdf2dcm utility will attempt to load DICOM data dictionaries specified
-in the \e DCMDICTPATH environment variable.  By default, i.e. if the
-\e DCMDICTPATH environment variable is not set, the file
-<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
-into the application (default for Windows).
-
-The default behavior should be preferred and the \e DCMDICTPATH environment
-variable only used when alternative data dictionaries are required.  The
-\e DCMDICTPATH environment variable has the same format as the Unix shell
-\e PATH variable in that a colon (":") separates entries.  On Windows systems,
-a semicolon (";") is used as a separator.  The data dictionary code will
-attempt to load each file specified in the \e DCMDICTPATH environment
-variable.
-It is an error if no data dictionary can be loaded.
+The \b pdf2dcm tool is deprecated.  Use \b dcmencap instead, which supports
+the same command line parameters, and more.
 
 \section pdf2dcm_see_also SEE ALSO
 
-<b>dcm2pdf</b>(1)
+<b>dcmencap</b>(1)
 
 \section pdf2dcm_copyright COPYRIGHT
 
-Copyright (C) 2005-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2005-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 4514b254615e5453a4f07c95e6348154edc9a476..70c9a984f2cfe876f37314bcbd0f1e20556dbf73 100644 (file)
@@ -14,279 +14,15 @@ stl2dcm [options] stlfile-in dcmfile-out
 
 \section stl2dcm_description DESCRIPTION
 
-The \b stl2dcm utility reads a STL file (\e stlfile-in), converts it to a
-DICOM Encapsulated STL Storage SOP instance and stores the converted data
-to an output file (\e dcmfile-out).
+The \b stl2dcm tool is deprecated.  Use \b dcmencap instead, which supports
+the same command line parameters, and more.
 
-\section stl2dcm_parameters PARAMETERS
+\section stl2dcm_see_also SEE ALSO
 
-\verbatim
-stlfile-in   STL input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-\endverbatim
-
-\section stl2dcm_options OPTIONS
-
-\subsection stl2dcm_general_options general options
-\verbatim
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-\endverbatim
-
-\subsection stl2dcm_dicom_document_options DICOM document options
-\verbatim
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-
-enhanced general equipment:
-
-  +mn  --manufacturer  [n]ame: string
-         manufacturer's name
-
-  +mm  --manufacturer-model  [n]ame: string
-         manufacturer's model name
-
-  +ds  --device-serial  [n]umber: string
-         device serial number
-
-  +sv  --software-versions  [v]ersions: string
-         software versions
-
-3d model measurement units:
-
-  +mu  --measurement-units  [CSD] [CV] [CM]: string
-         measurement units with coding scheme designator CSD,
-         code value CV and code meaning CM (default: UCUM, um, um)
-\endverbatim
-
-\subsection stl2dcm_processing_options processing options
-\verbatim
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-\endverbatim
-
-\subsection stl2dcm_output_options output options
-\verbatim
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-\endverbatim
-
-\section stl2dcm_notes NOTES
-
-\subsection stl2dcm_attribute_sources Attribute Sources
-
-The application may be fed with some additional input for filling mandatory
-(and optional) attributes in the new DICOM file like patient, study and series
-information:
-
-- The \e --key option can be used to add further attributes to the DICOM output
-  file.
-
-- It is also possible to specify sequences, items and nested attributes using
-  the \e --key option. In these cases, a special "path" notation has to be
-  used.  Details on this path notation can be found in the documentation of
-  \b dcmodify.
-
-- The \e --key option can be present more than once.
-
-- The value part (after the '=') may be absent causing the attribute to be set
-  with zero length.
-
-- Please be advised that the \e --key option is applied at the very end, just
-  before saving the DICOM file, so there is no value checking whatsoever.
-
-\section stl2dcm_logging LOGGING
-
-The level of logging output of the various command line tools and underlying
-libraries can be specified by the user.  By default, only errors and warnings
-are written to the standard error stream.  Using option \e --verbose also
-informational messages like processing details are reported.  Option
-\e --debug can be used to get more details on the internal activity, e.g. for
-debugging purposes.  Other logging levels can be selected using option
-\e --log-level.  In \e --quiet mode only fatal errors are reported.  In such
-very severe error events, the application will usually terminate.  For more
-details on the different logging levels, see documentation of module "oflog".
-
-In case the logging output should be written to file (optionally with logfile
-rotation), to syslog (Unix) or the event log (Windows) option \e --log-config
-can be used.  This configuration file also allows for directing only certain
-messages to a particular output stream and for filtering certain messages
-based on the module or application where they are generated.  An example
-configuration file is provided in <em>\<etcdir\>/logger.cfg</em>.
-
-\section stl2dcm_command_line COMMAND LINE
-
-All command line tools use the following notation for parameters: square
-brackets enclose optional values (0-1), three trailing dots indicate that
-multiple values are allowed (1-n), a combination of both means 0 to n values.
-
-Command line options are distinguished from parameters by a leading '+' or '-'
-sign, respectively.  Usually, order and position of command line options are
-arbitrary (i.e. they can appear anywhere).  However, if options are mutually
-exclusive the rightmost appearance is used.  This behavior conforms to the
-standard evaluation rules of common Unix shells.
-
-In addition, one or more command files can be specified using an '@' sign as a
-prefix to the filename (e.g. <em>\@command.txt</em>).  Such a command argument
-is replaced by the content of the corresponding text file (multiple
-whitespaces are treated as a single separator unless they appear between two
-quotation marks) prior to any further evaluation.  Please note that a command
-file cannot contain another command file.  This simple but effective approach
-allows one to summarize common combinations of options/parameters and avoids
-longish and confusing command lines (an example is provided in file
-<em>\<datadir\>/dumppat.txt</em>).
-
-\section stl2dcm_exit_codes EXIT CODES
-
-The \b stl2dcm utility uses the following exit codes when terminating.  This
-enables the user to check for the reason why the application terminated.
-
-\subsection stl2dcm_exit_codes_general general
-\verbatim
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-\endverbatim
-
-\subsection stl2dcm_exit_codes_input_file_errors input file errors
-\verbatim
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-\endverbatim
-
-\subsection stl2dcm_exit_codes_output_file_errors output file errors
-\verbatim
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-\endverbatim
-
-\section stl2dcm_environment ENVIRONMENT
-
-The \b stl2dcm utility will attempt to load DICOM data dictionaries specified
-in the \e DCMDICTPATH environment variable.  By default, i.e. if the
-\e DCMDICTPATH environment variable is not set, the file
-<em>\<datadir\>/dicom.dic</em> will be loaded unless the dictionary is built
-into the application (default for Windows).
-
-The default behavior should be preferred and the \e DCMDICTPATH environment
-variable only used when alternative data dictionaries are required.  The
-\e DCMDICTPATH environment variable has the same format as the Unix shell
-\e PATH variable in that a colon (":") separates entries.  On Windows systems,
-a semicolon (";") is used as a separator.  The data dictionary code will
-attempt to load each file specified in the \e DCMDICTPATH environment
-variable.
-It is an error if no data dictionary can be loaded.
+<b>dcmencap</b>(1)
 
 \section stl2dcm_copyright COPYRIGHT
 
-Copyright (C) 2018-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2018-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 6957ec8098657091ccca38e02323a940ac7917ba..fee5b9905bcf99fce1d40610eaf5af1b757f3ef3 100644 (file)
@@ -351,6 +351,6 @@ It is an error if no data dictionary can be loaded.
 
 \section xml2dcm_copyright COPYRIGHT
 
-Copyright (C) 2003-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2003-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 55712b930741d38a43f2c30c2bcadd43707a091c..17a622582027e6edf96b06036c614a7b297cd0be 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2019, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -475,7 +475,7 @@ private:
 /** @name string normalization flags.
  *  These flags can be used with normalizeString() to specify the extent of normalization.
  */
-//@{
+///@{
 
 /// delete trailing spaces
 const OFBool DELETE_TRAILING = OFTrue;
@@ -484,7 +484,7 @@ const OFBool DELETE_LEADING = OFTrue;
 /// handle string as multi-valued (components separated by a backslash)
 const OFBool MULTIPART = OFTrue;
 
-//@}
+///@}
 
 
 /* Function to get part out of a String for VM > 1 */
index 55fa5c59e6813ceaf375ab25eeb2beae36ff3472..8d5f4d0f1308e84c116ef9d875190a9b4ad09b36 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2023, OFFIS e.V.
+ *  Copyright (C) 1997-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -208,6 +208,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const = 0;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const = 0;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
@@ -510,6 +523,21 @@ public:
     DcmItem *dataset,
     OFString &decompressedColorModel);
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded.
+   *  @param fromType transfer syntax to decode from
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  static Uint16 decodedBitsAllocated(
+    const DcmXfer & fromType,
+    Uint16 bitsAllocated,
+    Uint16 bitsStored);
+
 private:
 
   /** constructor
index 22e53851f3ea45a91d43e4c934052948cb53862b..e85ada73aaff5f14264b71b959ae9a4f9028a68e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -380,6 +380,15 @@ class DCMTK_DCMDATA_EXPORT DcmDataset
      */
     virtual OFBool checkForSpecificCharacterSet() const { return OFTrue; }
 
+    /** initialize the OriginalXfer and CurrentXfer member variables.
+     *  This method sets the values for OriginalXfer (i.e. the transfer syntax
+     *  in which a dataset is or was originally read) and CurrentXfer
+     *  (i.e. the currently active transfer syntax).
+     *  The method should only be called during import operations.
+     *  @param xfer new value for OriginalXfer and CurrentXfer
+     */
+    void initializeXfer(const E_TransferSyntax xfer);
+
   protected:
 
     /** perform checks after reading of the dataset is considered complete. The
index 4fb52374a039b42728ace5c1fa0b30e249278812..a4eb586388131f00deda135f62ef8e674bd175de 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2024, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -804,6 +804,19 @@ class DCMTK_DCMDATA_EXPORT DicomDirInterface
                                                 const OFString &referencedFileID,
                                                 const OFFilename &sourceFilename);
 
+    /** create or update waveform presentation state record and copy required values
+     *  from dataset
+     *  @param record record to be updated, use NULL to create a new one
+     *  @param fileformat DICOM dataset of the current file
+     *  @param referencedFileID value of the Referenced File ID attribute
+     *  @param sourceFilename name of the source DICOM file
+     *  @return pointer to new or updated record, NULL if an error occurred
+     */
+    DcmDirectoryRecord *buildWfPresentationRecord(DcmDirectoryRecord *record,
+                                                  DcmFileFormat *fileformat,
+                                                  const OFString &referencedFileID,
+                                                  const OFFilename &sourceFilename);
+
     /** create or update waveform record and copy required values from dataset
      *  @param record record to be updated, use NULL to create a new one
      *  @param fileformat DICOM dataset of the current file
index 8f815767772da14a21d3de6b02e1dae49acef975..5e5475ede38a1edbcb6f0ee114767de7dc69fdd6 100644 (file)
@@ -4,7 +4,7 @@
 **
 **   User: joergr
 **   Host: thinkpad2
-**   Date: 2024-11-16 10:42:04
+**   Date: 2025-11-21 11:54:35
 **   Prog: /home/joergr/Source/dcmtk-full/public/dcmdata/libsrc/mkdeftag
 **
 **   From: ../data/dicom.dic
 
 #include "dcmtk/dcmdata/dctagkey.h"
 
-#define DCM_DICT_DEFTAG_BUILD_DATE "2024-11-16 10:42:04"
+#define DCM_DICT_DEFTAG_BUILD_DATE "2025-11-21 11:54:35"
 
 
 /*
 ** Fixed Tags in ascending (gggg,eeee) order.
-** Number of entries: 5206
+** Number of entries: 5266
 ** Tags with a repeating component (repeating tags) are listed later.
 */
 #define DCM_CommandGroupLength                   DcmTagKey(0x0000, 0x0000)
 #define DCM_FailedStudySequence                  DcmTagKey(0x0008, 0x119b)
 #define DCM_StudiesContainingOtherReferencedInstancesSequence DcmTagKey(0x0008, 0x1200)
 #define DCM_RelatedSeriesSequence                DcmTagKey(0x0008, 0x1250)
+#define DCM_PrincipalDiagnosisCodeSequence       DcmTagKey(0x0008, 0x1301)
+#define DCM_PrimaryDiagnosisCodeSequence         DcmTagKey(0x0008, 0x1302)
+#define DCM_SecondaryDiagnosesCodeSequence       DcmTagKey(0x0008, 0x1303)
+#define DCM_HistologicalDiagnosesCodeSequence    DcmTagKey(0x0008, 0x1304)
 #define DCM_RETIRED_LossyImageCompressionRetired DcmTagKey(0x0008, 0x2110)
 #define DCM_DerivationDescription                DcmTagKey(0x0008, 0x2111)
 #define DCM_SourceImageSequence                  DcmTagKey(0x0008, 0x2112)
 #define DCM_RecommendedDisplayFrameRateInFloat   DcmTagKey(0x0008, 0x9459)
 #define DCM_SkipFrameRangeFlag                   DcmTagKey(0x0008, 0x9460)
 #define DCM_PatientName                          DcmTagKey(0x0010, 0x0010)
+#define DCM_PersonNamesToUseSequence             DcmTagKey(0x0010, 0x0011)
+#define DCM_NameToUse                            DcmTagKey(0x0010, 0x0012)
+#define DCM_NameToUseComment                     DcmTagKey(0x0010, 0x0013)
+#define DCM_ThirdPersonPronounsSequence          DcmTagKey(0x0010, 0x0014)
+#define DCM_PronounCodeSequence                  DcmTagKey(0x0010, 0x0015)
+#define DCM_PronounComment                       DcmTagKey(0x0010, 0x0016)
 #define DCM_PatientID                            DcmTagKey(0x0010, 0x0020)
 #define DCM_IssuerOfPatientID                    DcmTagKey(0x0010, 0x0021)
 #define DCM_TypeOfPatientID                      DcmTagKey(0x0010, 0x0022)
 #define DCM_PatientDeathDateInAlternativeCalendar DcmTagKey(0x0010, 0x0034)
 #define DCM_PatientAlternativeCalendar           DcmTagKey(0x0010, 0x0035)
 #define DCM_PatientSex                           DcmTagKey(0x0010, 0x0040)
+#define DCM_GenderIdentitySequence               DcmTagKey(0x0010, 0x0041)
+#define DCM_SexParametersForClinicalUseCategoryComment DcmTagKey(0x0010, 0x0042)
+#define DCM_SexParametersForClinicalUseCategorySequence DcmTagKey(0x0010, 0x0043)
+#define DCM_GenderIdentityCodeSequence           DcmTagKey(0x0010, 0x0044)
+#define DCM_GenderIdentityComment                DcmTagKey(0x0010, 0x0045)
+#define DCM_SexParametersForClinicalUseCategoryCodeSequence DcmTagKey(0x0010, 0x0046)
+#define DCM_SexParametersForClinicalUseCategoryReference DcmTagKey(0x0010, 0x0047)
 #define DCM_PatientInsurancePlanCodeSequence     DcmTagKey(0x0010, 0x0050)
 #define DCM_PatientPrimaryLanguageCodeSequence   DcmTagKey(0x0010, 0x0101)
 #define DCM_PatientPrimaryLanguageModifierCodeSequence DcmTagKey(0x0010, 0x0102)
 #define DCM_RegionOfResidence                    DcmTagKey(0x0010, 0x2152)
 #define DCM_PatientTelephoneNumbers              DcmTagKey(0x0010, 0x2154)
 #define DCM_PatientTelecomInformation            DcmTagKey(0x0010, 0x2155)
-#define DCM_EthnicGroup                          DcmTagKey(0x0010, 0x2160)
+#define DCM_RETIRED_EthnicGroup                  DcmTagKey(0x0010, 0x2160)
 #define DCM_EthnicGroupCodeSequence              DcmTagKey(0x0010, 0x2161)
+#define DCM_EthnicGroups                         DcmTagKey(0x0010, 0x2162)
 #define DCM_Occupation                           DcmTagKey(0x0010, 0x2180)
 #define DCM_SmokingStatus                        DcmTagKey(0x0010, 0x21a0)
 #define DCM_AdditionalPatientHistory             DcmTagKey(0x0010, 0x21b0)
 #define DCM_ImageQualityIndicatorType            DcmTagKey(0x0014, 0x40a0)
 #define DCM_ImageQualityIndicatorMaterial        DcmTagKey(0x0014, 0x40a1)
 #define DCM_ImageQualityIndicatorSize            DcmTagKey(0x0014, 0x40a2)
+#define DCM_WaveDimensionsDefinitionSequence     DcmTagKey(0x0014, 0x4101)
+#define DCM_WaveDimensionNumber                  DcmTagKey(0x0014, 0x4102)
+#define DCM_WaveDimensionDescription             DcmTagKey(0x0014, 0x4103)
+#define DCM_WaveDimensionUnit                    DcmTagKey(0x0014, 0x4104)
+#define DCM_WaveDimensionValueType               DcmTagKey(0x0014, 0x4105)
+#define DCM_WaveDimensionValuesSequence          DcmTagKey(0x0014, 0x4106)
+#define DCM_ReferencedWaveDimension              DcmTagKey(0x0014, 0x4107)
+#define DCM_IntegerNumericValue                  DcmTagKey(0x0014, 0x4108)
+#define DCM_ByteNumericValue                     DcmTagKey(0x0014, 0x4109)
+#define DCM_ShortNumericValue                    DcmTagKey(0x0014, 0x410a)
+#define DCM_SinglePrecisionFloatingPointNumericValue DcmTagKey(0x0014, 0x410b)
+#define DCM_DoublePrecisionFloatingPointNumericValue DcmTagKey(0x0014, 0x410c)
 #define DCM_LINACEnergy                          DcmTagKey(0x0014, 0x5002)
 #define DCM_LINACOutput                          DcmTagKey(0x0014, 0x5004)
 #define DCM_ActiveAperture                       DcmTagKey(0x0014, 0x5100)
 #define DCM_VerificationDateTime                 DcmTagKey(0x0040, 0xa030)
 #define DCM_ObservationDateTime                  DcmTagKey(0x0040, 0xa032)
 #define DCM_ObservationStartDateTime             DcmTagKey(0x0040, 0xa033)
+#define DCM_EffectiveStartDateTime               DcmTagKey(0x0040, 0xa034)
+#define DCM_EffectiveStopDateTime                DcmTagKey(0x0040, 0xa035)
 #define DCM_ValueType                            DcmTagKey(0x0040, 0xa040)
 #define DCM_ConceptNameCodeSequence              DcmTagKey(0x0040, 0xa043)
 #define DCM_RETIRED_MeasurementPrecisionDescriptionTrial DcmTagKey(0x0040, 0xa047)
 #define DCM_CellValuesSequence                   DcmTagKey(0x0040, 0xa808)
 #define DCM_RETIRED_UniformResourceLocatorTrial  DcmTagKey(0x0040, 0xa992)
 #define DCM_WaveformAnnotationSequence           DcmTagKey(0x0040, 0xb020)
+#define DCM_StructuredWaveformAnnotationSequence DcmTagKey(0x0040, 0xb030)
+#define DCM_WaveformAnnotationDisplaySelectionSequence DcmTagKey(0x0040, 0xb031)
+#define DCM_ReferencedMontageIndex               DcmTagKey(0x0040, 0xb032)
+#define DCM_WaveformTextualAnnotationSequence    DcmTagKey(0x0040, 0xb033)
+#define DCM_AnnotationDateTime                   DcmTagKey(0x0040, 0xb034)
+#define DCM_DisplayedWaveformSegmentSequence     DcmTagKey(0x0040, 0xb035)
+#define DCM_SegmentDefinitionDateTime            DcmTagKey(0x0040, 0xb036)
+#define DCM_MontageActivationSequence            DcmTagKey(0x0040, 0xb037)
+#define DCM_MontageActivationTimeOffset          DcmTagKey(0x0040, 0xb038)
+#define DCM_WaveformMontageSequence              DcmTagKey(0x0040, 0xb039)
+#define DCM_ReferencedMontageChannelNumber       DcmTagKey(0x0040, 0xb03a)
+#define DCM_MontageName                          DcmTagKey(0x0040, 0xb03b)
+#define DCM_MontageChannelSequence               DcmTagKey(0x0040, 0xb03c)
+#define DCM_MontageIndex                         DcmTagKey(0x0040, 0xb03d)
+#define DCM_MontageChannelNumber                 DcmTagKey(0x0040, 0xb03e)
+#define DCM_MontageChannelLabel                  DcmTagKey(0x0040, 0xb03f)
+#define DCM_MontageChannelSourceCodeSequence     DcmTagKey(0x0040, 0xb040)
+#define DCM_ContributingChannelSourcesSequence   DcmTagKey(0x0040, 0xb041)
+#define DCM_ChannelWeight                        DcmTagKey(0x0040, 0xb042)
 #define DCM_TemplateIdentifier                   DcmTagKey(0x0040, 0xdb00)
 #define DCM_RETIRED_TemplateVersion              DcmTagKey(0x0040, 0xdb06)
 #define DCM_RETIRED_TemplateLocalVersion         DcmTagKey(0x0040, 0xdb07)
 #define DCM_ReferencedAssertionUID               DcmTagKey(0x0044, 0x0108)
 #define DCM_ApprovalSubjectSequence              DcmTagKey(0x0044, 0x0109)
 #define DCM_OrganizationalRoleCodeSequence       DcmTagKey(0x0044, 0x010a)
+#define DCM_RTAssertionsSequence                 DcmTagKey(0x0044, 0x0110)
 #define DCM_LensDescription                      DcmTagKey(0x0046, 0x0012)
 #define DCM_RightLensSequence                    DcmTagKey(0x0046, 0x0014)
 #define DCM_LeftLensSequence                     DcmTagKey(0x0046, 0x0015)
 #define DCM_PixelOriginInterpretation            DcmTagKey(0x0048, 0x0301)
 #define DCM_NumberOfOpticalPaths                 DcmTagKey(0x0048, 0x0302)
 #define DCM_TotalPixelMatrixFocalPlanes          DcmTagKey(0x0048, 0x0303)
+#define DCM_TilesOverlap                         DcmTagKey(0x0048, 0x0304)
 #define DCM_CalibrationImage                     DcmTagKey(0x0050, 0x0004)
 #define DCM_DeviceSequence                       DcmTagKey(0x0050, 0x0010)
 #define DCM_ContainerComponentTypeCodeSequence   DcmTagKey(0x0050, 0x0012)
 #define DCM_DVHMinimumDose                       DcmTagKey(0x3004, 0x0070)
 #define DCM_DVHMaximumDose                       DcmTagKey(0x3004, 0x0072)
 #define DCM_DVHMeanDose                          DcmTagKey(0x3004, 0x0074)
+#define DCM_DoseCalculationModelSequence         DcmTagKey(0x3004, 0x0080)
+#define DCM_DoseCalculationAlgorithmSequence     DcmTagKey(0x3004, 0x0081)
+#define DCM_CommissioningStatus                  DcmTagKey(0x3004, 0x0082)
+#define DCM_DoseCalculationModelParameterSequence DcmTagKey(0x3004, 0x0083)
+#define DCM_DoseDepositionCalculationMedium      DcmTagKey(0x3004, 0x0084)
 #define DCM_StructureSetLabel                    DcmTagKey(0x3006, 0x0002)
 #define DCM_StructureSetName                     DcmTagKey(0x3006, 0x0004)
 #define DCM_StructureSetDescription              DcmTagKey(0x3006, 0x0006)
 #define DCM_ScanningSpotSize                     DcmTagKey(0x300a, 0x0398)
 #define DCM_ScanSpotSizesDelivered               DcmTagKey(0x300a, 0x0399)
 #define DCM_NumberOfPaintings                    DcmTagKey(0x300a, 0x039a)
+#define DCM_ScanSpotGantryAngles                 DcmTagKey(0x300a, 0x039b)
+#define DCM_ScanSpotPatientSupportAngles         DcmTagKey(0x300a, 0x039c)
 #define DCM_IonToleranceTableSequence            DcmTagKey(0x300a, 0x03a0)
 #define DCM_IonBeamSequence                      DcmTagKey(0x300a, 0x03a2)
 #define DCM_IonBeamLimitingDeviceSequence        DcmTagKey(0x300a, 0x03a4)
index 7fb0022b865cf009823c264482cac4d85bdb1da7..57d6ab89982a84737088db138df31605b66ffda2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2023, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -132,7 +132,9 @@ typedef enum {
     /// annotation
     ERT_Annotation = 49,
     /// inventory
-    ERT_Inventory = 50
+    ERT_Inventory = 50,
+    /// wf presentation
+    ERT_WfPresentation = 51
 } E_DirRecType;
 
 
diff --git a/dcmdata/include/dcmtk/dcmdata/dcdocdec.h b/dcmdata/include/dcmtk/dcmdata/dcdocdec.h
new file mode 100644 (file)
index 0000000..856a9d6
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *
+ *  Copyright (C) 2007-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Marco Eichelberg, Tingyan Xu
+ *
+ *  Purpose: Helper class for extracting encapsulated file from DICOM encapsulated storage object
+ *
+ */
+
+#ifndef DCDOCDEC_H
+#define DCDOCDEC_H
+
+#include "dcmtk/config/osconfig.h"
+#include "dcmtk/dcmdata/dcdefine.h"   /* for DCMTK_DCMDATA_EXPORT */
+#include "dcmtk/dcmdata/dcfilefo.h"   /* for DcmFileFormat */
+
+/** Helper class for extracting the encapsulated document from a
+ *  DICOM encapsulated storage object to file
+ */
+class DCMTK_DCMDATA_EXPORT DcmDocumentDecapsulator
+{
+public:
+  /// Constructor
+  DcmDocumentDecapsulator();
+
+  /// Destructor
+  virtual ~DcmDocumentDecapsulator();
+
+  /** set the read mode for reading a DICOM file (default: ERM_autoDetect)
+   *  @param mode new read mode
+   */
+  void setReadMode(E_FileReadMode mode)
+  {
+      readMode_ = mode;
+  }
+
+  /** set the input transfer syntax for reading a DICOM file (default: EXS_Unknown)
+   *  @param xfer new input transfer syntax
+   */
+  void setInputXferSyntax(E_TransferSyntax xfer)
+  {
+      inputXfer_ = xfer;
+  }
+
+  /** set a command line string to be executed after the encapsulated document has been written to file
+   *  @param execString command line string
+   */
+  void setExecString(const char *execString)
+  {
+      execString_ = execString;
+  }
+
+  /** set the filename (path) for the DICOM file to be read
+   *  @param fname input file name
+   */
+  void setInputFile(const char *fname)
+  {
+      inputFname_ = fname;
+  }
+
+  /** set the filename (path) for the output file to be written
+   *  @param fname output file name
+   */
+  void setOutputFile(const char *fname)
+  {
+      outputFname_ = fname;
+  }
+
+  /** load the encapsulated DICOM file into memory.
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  OFCondition loadDICOMFile();
+
+  /** extract the encapsulated document, remove a pad byte if necessary,
+   *  and write the document to the output file
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  OFCondition writeEncapsulatedContentToFile();
+
+  /** execute the pre-defined command line, replacing the placeholder
+   *  "#f" with the actual output filename.
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  OFCondition executeCommand();
+
+private:
+
+  /// input file read mode
+  E_FileReadMode readMode_;
+
+  /// input transfer syntax
+  E_TransferSyntax inputXfer_;
+
+  /// command line string to be executed
+  const char *execString_;
+
+  /// input filename
+  const char *inputFname_;
+
+  /// output filename
+  const char *outputFname_;
+
+  /// DICOM file
+  DcmFileFormat dicomFile_;
+
+};
+
+#endif // DCDOCDEC_H
index 2978e961806368a0dbe77a4ddd4bbbf4dfcfac67..ae88f5eb3557e79b30f98518084a1ec26ff7b1eb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -578,6 +578,28 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putFloat32(const Float32 val, const unsigned long pos = 0);
 
+    /** insert into the element value a copy of the given Sint64 value. If the
+     *  attribute is multi-valued, all other values remain untouched.
+     *  Requires element to be of corresponding VR, otherwise an error is returned.
+     *  @param val new value to be inserted
+     *  @param pos position for insert operation. Value: pos <= getVM(), i.e. a value
+     *    can be appended to the end of the current element or inserted within the
+     *    existing value field.
+     *  @return EC_Normal upon success, an error code otherwise
+     */
+    virtual OFCondition putSint64(const Sint64 val, const unsigned long pos = 0);
+
+    /** insert into the element value a copy of the given Uint64 value. If the
+     *  attribute is multi-valued, all other values remain untouched.
+     *  Requires element to be of corresponding VR, otherwise an error is returned.
+     *  @param val new value to be inserted
+     *  @param pos position for insert operation. Value: pos <= getVM(), i.e. a value
+     *    can be appended to the end of the current element or inserted within the
+     *    existing value field.
+     *  @return EC_Normal upon success, an error code otherwise
+     */
+    virtual OFCondition putUint64(const Uint64 val, const unsigned long pos = 0);
+
     /** insert into the element value a copy of the given Float64 value. If the
      *  attribute is multi-valued, all other values remain untouched.
      *  Requires element to be of corresponding VR, otherwise an error is returned.
@@ -600,7 +622,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putTagVal(const DcmTagKey &attrTag, const unsigned long pos = 0);
 
-    /** replace the element value by a copy of the given Uint8 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Uint8 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -608,7 +631,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putUint8Array(const Uint8 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Sint16 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Sint16 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -616,7 +640,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putSint16Array(const Sint16 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Uint16 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Uint16 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -624,7 +649,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putUint16Array(const Uint16 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Sint32 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Sint32 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -632,7 +658,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putSint32Array(const Sint32 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Uint32 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Uint32 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -640,7 +667,8 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putUint32Array(const Uint32 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Float32 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Float32 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -648,7 +676,26 @@ class DCMTK_DCMDATA_EXPORT DcmElement
      */
     virtual OFCondition putFloat32Array(const Float32 *vals, const unsigned long num);
 
-    /** replace the element value by a copy of the given Float64 array (which is possibly multi-valued).
+    /** replace the element value by a copy of the given Sint64 array (which is
+     *  possibly multi-valued).
+     *  Requires element to be of corresponding VR, otherwise an error is returned.
+     *  @param vals new attribute value
+     *  @param num number of values in array vals
+     *  @return EC_Normal upon success, an error code otherwise
+     */
+    virtual OFCondition putSint64Array(const Sint64 *vals, const unsigned long num);
+
+    /** replace the element value by a copy of the given Uint64 array (which is
+     *  possibly multi-valued).
+     *  Requires element to be of corresponding VR, otherwise an error is returned.
+     *  @param vals new attribute value
+     *  @param num number of values in array vals
+     *  @return EC_Normal upon success, an error code otherwise
+     */
+    virtual OFCondition putUint64Array(const Uint64 *vals, const unsigned long num);
+
+    /** replace the element value by a copy of the given Float64 array (which is
+     *  possibly multi-valued).
      *  Requires element to be of corresponding VR, otherwise an error is returned.
      *  @param vals new attribute value
      *  @param num number of values in array vals
@@ -896,6 +943,19 @@ class DCMTK_DCMDATA_EXPORT DcmElement
     static OFCondition checkVM(const unsigned long vmNum,
                                const OFString &vmStr);
 
+    /** determines the effective value of BitsAllocated that a dataset will have
+     *  after decompression of an image with the given values for bitsAllocated
+     *  and bitsStored. This may differ from the bitsAllocated parameter for example
+     *  if that value is not a multiple of 8. Returns zero if an image with the
+     *  given parameters cannot be decoded.
+     *  @param bitsAllocated current value of Bits Allocated
+     *  @param bitsStored current value of Bits Stored
+     *  @return effective value of BitsAllocated, 0 if no decompression possible
+     */
+    virtual Uint16 decodedBitsAllocated(
+      Uint16 bitsAllocated,
+      Uint16 bitsStored) const;
+
   protected:
 
     /** This function returns this element's value. The returned value corresponds to the
index 97e6cebe90f381d5a599d1ef79f55b9e2c18454e..4c307adc8cdad9303281f3ac164d11cdfd371391 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2021, OFFIS e.V.
+ *  Copyright (C) 2018-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -13,7 +13,7 @@
  *
  *  Module:  dcmdata
  *
- *  Author:  Pedro Arizpe
+ *  Author:  Pedro Arizpe, Marco Eichelberg
  *
  *  Purpose: Class to control document encapsulation into DICOM files
  *
 #ifndef DCENCDOC_H
 #define DCENCDOC_H
 
-//make sure OS specific configuration is included first
-#include "dcmtk/config/osconfig.h"
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 #include "dcmtk/ofstd/ofstring.h"     /* for class OFString */
 #include "dcmtk/ofstd/ofcond.h"       /* for class OFCondition */
 #include "dcmtk/dcmdata/dcdefine.h"   /* for DCMTK_DCMDATA_EXPORT */
 #include "dcmtk/dcmdata/dcfilefo.h"   /* for class DcmFileFormat */
 #include "dcmtk/ofstd/ofcmdln.h"      /* for OFCmdUnsignedInt */
 
-struct XMLNode;
 class OFCommandLine;
 class OFConsoleApplication;
-class OFLogger;
+class DcmItem;
 
-/** This class handles common functions of all command line applications
- *  for document encapsulation.
+/** This class handles common functions for the conversion of
+ *  documents into encapsulated DICOM SOP instances.
  */
 class DCMTK_DCMDATA_EXPORT DcmEncapsulatedDocument
 {
 public:
-  ///Constructor
-  DcmEncapsulatedDocument();
-
-  ///Destructor
-  ~DcmEncapsulatedDocument();
-
-  /** This function is only used to process CDA files.
-   *  It retrieves all entries of an attribute and returns them separated by backslashes.
-   *  @param fileNode the root XML node.
-   *  @param attr the attribute to search for.
-   *  @return OFstring containing all entries found, separated by double backslashes
-   */
-  OFString XMLgetAllAttributeValues(XMLNode fileNode, OFString attr);
-
-  /** This function is only used to process CDA files.
-   *  It retrieves the value from the CDA document
-   *  corresponding to the DCM Tag. According to Standard v. 2013 part20/sect_A.8.
-   *  @param fileNode the root XML node.
-   *  @param attr the tag to search for in the CDA file.
-   *  @return OFstring containing the value of the corresponding tag.
-   */
-  OFString XMLgetAttribute(XMLNode fileNode, DcmTagKey attr);
-
-  /** Retrieves patient, concept and document data from the CDA file and checks for data conflicts
-   *  with series, study and user input. It also retrieves all mediatypes found in the CDA document.
-   *  @param filename The filename of the CDA document.
-   *  @param appLogger The logger of the application calling this method.
-   *  @return EXITCODE_NO_ERROR (0) if successful or error code in case of failure.
-   */
-  int getCDAData(const char *filename, OFLogger &appLogger);
-
-  /** Recursive function used by getAttributeValues to get all occurrences of an attribute as list.
-   *  @param currnode the current XML node to be processed.
-   *  @param results a pointer to the list of strings where the results should be stored.
-   *  @param attr the attribute to search for.
-   *  @return OFTrue if the attribute value was found, OFFalse otherwise.
-   */
-  OFBool XMLsearchAttribute(XMLNode currnode, OFList<OFString> *results, OFString attr);
-
-  /** Add CDA specific command line options to the OFCommandLine object
-   *  passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addCDACommandlineOptions(OFCommandLine& cmd);
-
-  /** Add PDF specific command line options to the OFCommandLine object
-   *  passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addPDFCommandlineOptions(OFCommandLine& cmd);
-
-  /** Add STL specific command line options to the OFCommandLine object
-   *  passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addSTLCommandlineOptions(OFCommandLine& cmd);
-
-  /** Add general command line options to the OFCommandLine object
-   *  passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addGeneralOptions(OFCommandLine &cmd);
-
-  /** Add command line options specific for documents to the OFCommandLine
-   *  object passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addDocumentOptions(OFCommandLine &cmd);
-
-  /** Add command line options specific for output to the OFCommandLine
-   *  object passed to the constructor.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void addOutputOptions(OFCommandLine &cmd);
-
-  /** Parse and evaluate the given command line arguments.
-   *  @param app a reference to an OFConsoleApplication object used in the
-   *    calling application.
-   *  @param cmd a reference to an OFCommandLine object used to parse
-   *    the command line argument give to the calling application.
-   *  @return none.
-   */
-  void parseArguments(OFConsoleApplication& app, OFCommandLine& cmd);
-
-  /** Includes basic information into the DICOM file.
-   *  @param dataset a reference to a DcmItem containing the information to be included.
-   *  @param logger The logger of the application calling this method.
-   *  @return EC_Normal if successful, an error code otherwise.
-   */
-  OFCondition createHeader (DcmItem *dataset,
-    OFLogger& logger);
-
-  /** Correctly inserts encapsulated document data.
-   *  @param dataset The dataset to which we should encapsulate this document.
-   *  @param logger The logger of the application calling this method.
-   *  @return EXITCODE_NO_ERROR (0) if successful or error code in case of failure.
-   */
-  int insertEncapsulatedDocument(DcmItem *dataset,
-    OFLogger& logger);
-
-  /** Get study or series data from provided file. Generate UID if none present.
-   *  @param appLogger The logger of the application calling this method.
-   *  @return EC_Normal if successful, an error code otherwise.
-   */
-  OFCondition createIdentifiers(OFLogger& appLogger);
-
-  /** Copy override keys over existing keys in given dataset.
-   *  @param outputDset dataset to which the override keys are copied
-   *  @return EC_Normal if successful, an error code otherwise.
-   */
-  OFCondition applyOverrideKeys(DcmDataset *outputDset);
-
-  /** Specifies some attributes that should be inserted after encapsulation
-   *  They will override any identical attributes already existing in the resulting encapsulated
-   *  DICOM object. The override keys are applied at the very end of the conversion and do not
-   *  undergo any validity checking.
-   *  @param ovkeys override keys that can be tags, dictionary names and paths (see DcmPath
-   *  for syntax). Also it is permitted to set a value if appropriate, e. g. "PatientName=Doe^John"
-   *  would be a valid overridekey.
-   *  @return none.
-   */
-  void setOverrideKeys(const OFList<OFString>& ovkeys);
-
-  /** Returns the input file name.
-   *  @return the input file name as OFString.
-   */
-  OFString getInputFileName();
-
-  /** Sets the input file name to the given string.
-   *  @param fName the file name to be set.
-   *  @return none.
-   */
-  void setInputFileName(OFString fName);
-
-  /** Returns the output file name.
-   *  @return the output file name as OFString.
-   */
-  OFString getOutputFileName();
-
-  /** Sets the output file name.
-   *  @param fName the file name to be set.
-   *  @return none.
-   */
-  void setOutputFileName(OFString fName);
-
-  /** Attempt to save the output file .
-   *  @param fileformat the DICOM Fileformat including the output file params.
-   *  @return Error code as condition, if error occurs, EC_Normal otherwise.
-   */
-  OFCondition saveFile(DcmFileFormat fileformat);
-
-  /** Returns the transfer syntax.
-   *  @return the transfer syntax as E_TransferSyntax.
-   */
-  E_TransferSyntax getTransferSyntax();
-
-  /** Returns the current filetype.
-   *  @return the current filetype as OFString.
-   */
-  OFString getFileType();
-
-  /** Sets the current filetype.
-   *  @param fType the current filetype.
-   *  @return none.
-   */
-  void setFileType(OFString fType);
+
+    /// document type of encapsulated document
+    enum DocumentType
+    {
+        /// PDF document
+        DT_pdfDocument,
+        /// CDA document
+        DT_cdaDocument,
+        /// STL document
+        DT_stlDocument,
+        /// MTL document
+        DT_mtlDocument,
+        /// OBJ document
+        DT_objDocument,
+        /// unknown document
+        DT_unknownDocument,
+    };
+
+    ///Constructor
+    DcmEncapsulatedDocument();
+
+    ///Destructor
+    ~DcmEncapsulatedDocument();
+
+    /** Add CDA specific command line options to the OFCommandLine object
+     *  passed to the constructor.
+     *  @param cmd a reference to an OFCommandLine object used to parse
+     *    the command line argument give to the calling application.
+     *  @return none.
+     */
+    void addCommandlineOptions(OFCommandLine& cmd) const;
+
+    /** Parse and evaluate the given command line arguments.
+     *  @param app a reference to an OFConsoleApplication object used in the
+     *    calling application.
+     *  @param cmd a reference to an OFCommandLine object used to parse
+     *    the command line argument give to the calling application.
+     *  @return none.
+     */
+    void parseArguments(OFConsoleApplication& app, OFCommandLine& cmd);
+
+    /** Identify document format and insert encapsulated document data
+     *  into the dataset
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition insertEncapsulatedDocument();
+
+    /** Get study or series data from series file. Generate UID if none present.
+     *  @note This method should be called after insertEncapsulatedDocument()
+     *  to make sure that the document format has been identified.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition createIdentifiers();
+
+    /** Perform format specific processing such as extracting information
+     *  from the document content.
+     *  @note This method should be called after insertEncapsulatedDocument()
+     *    and after createIdentifiers() to make sure that the document format
+     *    has been identified and inconsistencies between DICOM and document
+     *    level can be checked.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition formatSpecificProcessing();
+
+    /** Write header fields to the DICOM dataset
+     *  @note This method should be called after insertEncapsulatedDocument()
+     *  to make sure that the document format has been identified.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition createHeader();
+
+    /** Copy override keys over existing keys in given dataset.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition applyOverrideKeys();
+
+    /** Returns the input file name.
+     *  @return the input file name as OFString.
+     */
+    OFString getInputFileName();
+
+    /** Returns the output file name.
+     *  @return the output file name as OFString.
+     */
+    OFString getOutputFileName();
+
+    /** Save the output file.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition saveFile();
 
 private:
-  ///input file name
-  OFString             opt_ifname;
-  ///output file name
-  OFString             opt_ofname;
-
-  ///optional parameters
-  ///*patient data
-  OFString             opt_patientBirthdate;
-  OFString             opt_patientID;
-  OFString             opt_patientName;
-  OFString             opt_patientSex;
-  ///*concept data
-  OFString             opt_conceptCM;
-  OFString             opt_conceptCSD;
-  OFString             opt_conceptCV;
-  ///*document specific options
-  OFString             opt_documentTitle;
-  OFString             opt_seriesFile;
-  OFString             opt_seriesUID;
-  OFString             opt_studyUID;
-
-  ///*assign default values for file encoding and padding
-  E_EncodingType          opt_oenctype;
-  E_FileWriteMode         opt_writeMode;
-  E_GrpLenEncoding        opt_oglenc;
-  E_PaddingEncoding       opt_opadenc;
-  E_TransferSyntax        opt_oxfer;
-  OFCmdUnsignedInt        opt_filepad;
-  OFCmdUnsignedInt        opt_itempad;
-  ///*pre-existing series
-  OFBool                  opt_readSeriesInfo;
-  OFBool                  opt_annotation;
-  OFBool                  opt_increment;
-
-  OFCmdSignedInt          opt_instance;
-  /** These attributes are applied to the dataset after conversion
-   * (They are not checked by the isValid() function).
-   */
-  OFList<OFString>        opt_overrideKeys;
-
-  ///CDA specific variables
-  OFString                cda_mediaTypes;
-  OFString                hl7_InstanceIdentifier;
-  OFBool                  opt_override;
-
-  /// STL specific variables
-  /// Frame of Reference module
-  OFString                opt_frameOfReferenceUID;
-  OFString                opt_positionReferenceIndicator;
-  ///Enhanced general equipment module
-  /// Manufacturer (VM 1)
-  OFString                opt_manufacturer;
-  /// Manufacturer's Model Name (VM 1)
-  OFString                opt_manufacturerModelName;
-  /// Device Serial Number (VM 1)
-  OFString                opt_deviceSerialNumber;
-  /// Software Version(s) (VM 1-n)
-  OFString                opt_softwareVersions;
-
-  /// Manufacturing 3D Model Module
-  /// 3d Model Measurement Units Code Meaning
-  OFString                opt_measurementUnitsCM;
-  /// 3d Model Measurement Units Code Scheme Designator
-  OFString                opt_measurementUnitsCSD;
-  /// 3d Model Measurement Units Code Value
-  OFString                opt_measurementUnitsCV;
-
-  ///Type of file currently being converted.
-  OFString ftype;
+
+    /** Retrieve patient, concept and document data from a CDA file and check for conflicts
+     *  with series, study and user input. Also retrieve all mediatypes found in the CDA document.
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition getCDAData();
+
+    /** Add mandatory Frame of Reference Module attributes to dataset.
+     *  @param dataset output dataset
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition addFrameOfReferenceModule(DcmItem *dataset);
+
+    /** Add mandatory Enhanced General Equipment Module attributes to dataset.
+     *  @param dataset output dataset
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition addEnhancedGeneralEquipmentModule(DcmItem *dataset);
+
+    /** Add mandatory Manufacturing 3D Model Module attributes to dataset.
+     *  @param dataset output dataset
+     *  @return EC_Normal if successful, an error code otherwise.
+     */
+    OFCondition addManufacturing3DModelModule(DcmItem *dataset);
+
+    ///input file name
+    OFString             ifname_;
+
+    ///output file name
+    OFString             ofname_;
+
+    /// patient's birth date
+    OFString             patientBirthdate_;
+
+    /// patient ID
+    OFString             patientID_;
+
+    /// patient name
+    OFString             patientName_;
+
+    /// patient's sex
+    OFString             patientSex_;
+
+    /// document title: code meaning
+    OFString             conceptCM_;
+
+    /// document title: code scheme designator
+    OFString             conceptCSD_;
+
+    /// document title: code value
+    OFString             conceptCV_;
+
+    /// document title
+    OFString             documentTitle_;
+
+    /// file to read series data from
+    OFString             seriesFile_;
+
+    /// series instance UID
+    OFString             seriesUID_;
+
+    /// study instance UID
+    OFString             studyUID_;
+
+    /// specific character set (from series file)
+    OFString             specificCharSet_;
+
+    /// modality (from series file)
+    OFString             modality_;
+
+    /// DICOM sequence encoding: explicit or undefined length
+    E_EncodingType          oenctype_;
+
+    /// write mode for the DICOM file
+    E_FileWriteMode         writeMode_;
+
+    /// handling of group length encoding
+    E_GrpLenEncoding        oglenc_;
+
+    /// handling of data set trailing padding
+    E_PaddingEncoding       opadenc_;
+
+    /// transfer syntax for the DICOM file
+    E_TransferSyntax        oxfer_;
+
+    /// padding for the main dataset
+    OFCmdUnsignedInt        filepad_;
+
+    /// padding for sequence items
+    OFCmdUnsignedInt        itempad_;
+
+    /// true if we are supposed to read series information from another DICOM file
+    OFBool                  readSeriesInfo_;
+
+    /// burned-in annotation present?
+    OFBool                  annotation_;
+
+    /// increment instance number from given DICOM series file?
+    OFBool                  increment_;
+
+    /// instance number
+    OFCmdSignedInt          instance_;
+
+    /// list of DICOM attributes and attribute values to be applied after conversion
+    OFList<OFString>        overrideKeys_;
+
+    // CDA specific variables
+
+    /// CDA media types
+    OFString                cda_mediaTypes;
+
+    /// CDA instance identifier
+    OFString                hl7_InstanceIdentifier;
+
+    /// should CDA header values override DICOM values?
+    OFBool                  override_;
+
+    // STL/MTL/OBJ specific variables
+    // Frame of Reference module
+
+    /// frame of reference UID
+    OFString                frameOfReferenceUID_;
+
+    /// position reference indicator
+    OFString                positionReferenceIndicator_;
+
+    // Enhanced general equipment module
+
+    /// manufacturer
+    OFString                manufacturer_;
+
+    /// manufacturer's model name
+    OFString                manufacturerModelName_;
+
+    /// device serial number
+    OFString                deviceSerialNumber_;
+
+    /// software version(s) (VM 1-n)
+    OFString                softwareVersions_;
+
+    // Manufacturing 3D Model Module
+
+    /// 3D model measurement units code meaning
+    OFString                measurementUnitsCM_;
+
+    /// 3D model measurement units code scheme designator
+    OFString                measurementUnitsCSD_;
+
+    /// 3D model measurement units code value
+    OFString                measurementUnitsCV_;
+
+    /// Type of file currently being converted.
+    DocumentType ftype_;
+
+    /// DICOM file
+    DcmFileFormat dfile_;
 };
+
 #endif // DCENCDOC_H
index cca50b209c45b12c09141b3dc99ee7b55ea4d3b3..c8ba944bfedc46b23258a256f7594b550b3716e1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2022, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -80,7 +80,8 @@ const unsigned short OFM_dcmect   = 35;
  *  These constants can be used in addition to the general purpose ones
  *  defined in module ofstd.
  */
-//@{
+///@{
+
 /// Invalid tag
 extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_InvalidTag;
 /// Tag not found
@@ -179,16 +180,32 @@ extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CannotWriteJsonInlineBinar
 extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_XMLParseError;
 /// XML validation failure
 extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_XMLValidationFailure;
-/// SOP class mismatch
+/// SOP Class mismatch
 extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_SOPClassMismatch;
 /// Unknown UID name: No mapping to UID value defined
 extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_UnknownUIDName;
 /// Cannot write IS/DS string as JSON number
-extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CannotWriteStringAsJsonNumber;
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CannotWriteStringAsJSONNumber;
+/// Cannot write bulk data file
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CannotWriteBulkDataFile;
+/// JSON encoding not supported for encapsulated multi-frame pixel data
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CannotWriteJSONMultiframe;
+/// Not the expected Type while parsing the JSON file
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_InvalidJSONType;
+/// Invalid JSON content
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_InvalidJSONContent;
+/// BulkDataURI not yet supported
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_BulkDataURINotSupported;
+/// Unsupported URI type
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_UnsupportedURIType;
+/// Execution of command line failed
+extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CommandLineFailed;
 
-//@}
+///@}
 
-// status code constants
+/** @name status code constants for module dcmdata.
+ */
+///@{
 
 /// error, cannot select specific character set
 extern DCMTK_DCMDATA_EXPORT const unsigned short EC_CODE_CannotSelectCharacterSet;
@@ -199,4 +216,6 @@ extern DCMTK_DCMDATA_EXPORT const unsigned short EC_CODE_CannotConvertToXML;
 /// error, cannot determine start fragment (of compressed pixel data)
 extern DCMTK_DCMDATA_EXPORT const unsigned short EC_CODE_CannotDetermineStartFragment;
 
+///@}
+
 #endif /* !DCERROR_H */
index ca901e7f574854e5d37f23b8926ab5177591c974..452aa1dd0fdfdb197cba7e2d92956e1ee09898b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #define DCFILEFO_H
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
-
 #include "dcmtk/dcmdata/dcsequen.h"
 #include "dcmtk/dcmdata/dcdatset.h"
 
-
 // forward declarations
 class DcmMetaInfo;
 class DcmJsonFormat;
@@ -390,6 +388,20 @@ class DCMTK_DCMDATA_EXPORT DcmFileFormat
         FileReadMode = readMode;
     }
 
+    /** set Implementation Class UID to be used when writing the file
+     *  (unless the write mode EWM_dontUpdateMeta is used,
+     *  in which case the metaheader is not updated.)
+     *  @param implementationClassUID implementation class UID
+     */
+    void setImplementationClassUID(const OFString& implementationClassUID);
+
+    /** set Implementation Version Name to be used when writing the file
+     *  (unless the write mode EWM_dontUpdateMeta is used,
+     *  in which case the metaheader is not updated.)
+     *  @param implementationVersionName implementation version name
+     */
+    void setImplementationVersionName(const OFString& implementationVersionName);
+
     /** method inherited from base class that shall not be used for instances of this class.
      *  Method immediately returns with error code.
      *  @param item item
@@ -481,12 +493,12 @@ class DCMTK_DCMDATA_EXPORT DcmFileFormat
      *  @param writeMode flag indicating whether to update the file meta information or not
      *  @return EC_Normal if successful, an error code otherwise
      */
-    static OFCondition checkMetaHeaderValue(DcmMetaInfo *metainfo,
+    OFCondition checkMetaHeaderValue(DcmMetaInfo *metainfo,
                                             DcmDataset *dataset,
                                             const DcmTagKey &atagkey,
                                             DcmObject *obj,
                                             const E_TransferSyntax oxfer,
-                                            const E_FileWriteMode writeMode);
+                                            const E_FileWriteMode writeMode) const;
 
     /** read DCM_TransferSyntaxUID from meta header dataset and return as E_TransferSyntax value
      *  @param metainfo meta-header dataset
@@ -496,6 +508,12 @@ class DCMTK_DCMDATA_EXPORT DcmFileFormat
 
     /// file read mode, specifies whether to read the meta header or not
     E_FileReadMode FileReadMode;
+
+    /// implementation class UID to write in the meta-header
+    OFString ImplementationClassUID;
+
+    /// implementation version name to write in the meta-header
+    OFString ImplementationVersionName;
 };
 
 
index a296c1c969618959dd865404126893bf7e108da3..84d2b6f3bf88779f95c88cdcf7fd7b402415eea5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -353,6 +353,10 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  (separated by a backslash) code extension techniques are used and escape sequences
      *  may be encountered in the source string to switch between the specified character
      *  sets.
+     *  @note The conversion code does not perform a thorough validation of the strings to
+     *    be converted. For example, characters that are permitted in the source character
+     *    set but forbidden in DICOM (such as byte positions 0x80-0x9F in ISO_IR 100) may
+     *    be converted without warning or error.
      *  @param fromCharset name of the source character set(s) used for the conversion
      *  @param toCharset name of the destination character set used for the conversion.
      *    Only a single value is permitted (i.e. no code extensions).
@@ -375,11 +379,15 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  character set can be found in the DICOM standard, e.g. "ISO_IR 100" for ISO 8859-1
      *  (Latin 1) or "ISO_IR 192" for Unicode in UTF-8. An empty string denotes the
      *  default character repertoire, which is ASCII (7-bit).
+     *  @note The conversion code does not perform a thorough validation of the strings to
+     *    be converted. For example, characters that are permitted in the source character
+     *    set but forbidden in DICOM (such as byte positions 0x80-0x9F in ISO_IR 100) may
+     *    be converted without warning or error.
      *  @param toCharset name of the destination character set used for the conversion.
      *    Only a single value is permitted (i.e. no code extensions).
      *  @param flags optional flag used to customize the conversion (see DCMTypes::CF_xxx)
-     *  @param ignoreCharset if OFTrue, the value of SpecificCharacterSet is ignored.
-     *    Also see checkForSpecificCharacterSet().
+     *  @param ignoreCharset if OFTrue, the value of SpecificCharacterSet is ignored,
+     *    otherwise the element value is updated. Also see checkForSpecificCharacterSet().
      *  @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition convertCharacterSet(const OFString &toCharset,
@@ -388,7 +396,11 @@ class DCMTK_DCMDATA_EXPORT DcmItem
 
     /** convert all element values that are contained in this item and that are affected
      *  by SpecificCharacterSet from the currently selected source character set to the
-     *  currently selected destination character set
+     *  currently selected destination character set.
+     *  @note The conversion code does not perform a thorough validation of the strings to
+     *    be converted. For example, characters that are permitted in the source character
+     *    set but forbidden in DICOM (such as byte positions 0x80-0x9F in ISO_IR 100) may
+     *    be converted without warning or error.
      *  @param converter character set converter to be used to convert the element values
      *  @return status, EC_Normal if successful, an error code otherwise
      */
@@ -403,6 +415,17 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      */
     virtual OFCondition convertToUTF8();
 
+    /** update the SpecificCharacterSet (0008,0005) element depending on the given
+     *  parameters. The current value of this element is either replaced or a new
+     *  element is inserted or the existing element is deleted.
+     *  @note This method is called by convertCharacterSet() and convertToUTF8() when
+     *    needed, so there is usually no reason to call it directly.
+     *  @param status error status of previous operations (might also be updated)
+     *  @param converter character set converter used to convert element values
+     */
+    virtual void updateSpecificCharacterSet(OFCondition &status,
+                                            const DcmSpecificCharacterSet &converter);
+
     /** insert a new element into the list of elements maintained by this item.
      *  The list of elements is always kept in ascending tag order.
      *  @param elem element to be inserted, must not be contained in this or
@@ -599,8 +622,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
     /* --- findAndGet functions: find an element and get it or the value, respectively --- */
 
     /** find element and get a pointer to it (or copy it).
-     *  Applicable to all DICOM value representations (VR).
      *  The result variable 'element' is automatically set to NULL if an error occurs.
+     *  @note Applicable to all DICOM value representations (VR).
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param element variable in which the reference to (or copy of) the element is stored
      *  @param searchIntoSub flag indicating whether to search into sequences or not
@@ -614,6 +637,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
 
     /** find all elements matching a particular tag and return references to them on a stack.
      *  This functions always performs a deep search (i.e. searches into sequence of items).
+     *  @note Applicable to all DICOM value representations (VR).
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param resultStack stack where references to the elements are stored (added to).
      *    If no element is found, the stack is not modified (e.g. cleared).
@@ -623,11 +647,11 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    DcmStack &resultStack);
 
     /** find element and get value as a reference to a C string. NB: The string is not copied!
-     *  Applicable to the following VRs: AE, AS, CS, DA, DS, DT, IS, LO, LT, PN, SH, ST, TM, UC, UI,
-     *  UR, UT.
      *  Since the getString() routine is called internally the resulting string reference represents
      *  the (possibly multi-valued) value as stored in the dataset, i.e. no normalization is performed.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: AE, AS, CS, DA, DS, DT, IS, LO, LT, PN, SH, ST, TM,
+     *    UC, UI, UR, UT.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored (might be NULL)
      *  @param searchIntoSub flag indicating whether to search into sequences or not
@@ -638,14 +662,14 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a reference to a C string. NB: The string is not copied!
-     *  Applicable to the following VRs: AE, AS, CS, DA, DS, DT, IS, LO, LT, PN, SH, ST, TM, UC, UI,
-     *  UR, UT.
      *  Since the getString() routine is called internally the resulting string reference represents
      *  the (possibly multi-valued) value as stored in the dataset, i.e. no normalization is performed.
      *  The result variable 'value' is automatically set to NULL and 'length' is set to 0 if an error
      *  occurs.
      *  Please note that since the length is returned separately, the string value can contain more
      *  than one NULL byte.
+     *  @note Applicable to the following VRs: AE, AS, CS, DA, DS, DT, IS, LO, LT, PN, SH, ST, TM,
+     *    UC, UI, UR, UT.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored (might be NULL)
      *  @param length length of the string (number of characters without the trailing NULL byte)
@@ -658,8 +682,6 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a C++ string (only one component).
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  Since the getOFString() routine is called internally the resulting string is normalized, i.e.
      *  leading and/or trailing spaces are removed according to the associated value representation,
      *  or the element value is converted to a character string (for non-string VRs) - see documentation
@@ -667,6 +689,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  In contrast to the above and below function only the specified component (see parameter 'pos')
      *  is returned. The result variable 'value' is automatically set to an empty string if an error
      *  occurs.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD,
+     *    OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -679,13 +703,13 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a C++ string (all components).
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  Since the getOFStringArray() routine is called internally the resulting string is normalized,
      *  i.e. leading and/or trailing spaces are removed according to the associated value representation
      *  or the element values are converted to character strings (for non-string VRs) - see documentation
      *  in the corresponding header file.
      *  The result variable 'value' is automatically set to an empty string if an error occurs.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD,
+     *    OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param searchIntoSub flag indicating whether to search into sequences or not
@@ -696,8 +720,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                         const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an unsigned 8-bit integer.
-     *  Applicable to the following VRs: OB.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: OB.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -710,8 +734,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                 const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of unsigned 8-bit integers.
-     *  Applicable to the following VRs: OB.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: OB.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -724,8 +748,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                      const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an unsigned 16-bit integer.
-     *  Applicable to the following VRs: OW, US.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: OW, US.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -738,8 +762,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of unsigned 16-bit integers.
-     *  Applicable to the following VRs: AT, OW, US.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: AT, OW, US.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -752,8 +776,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a signed 16-bit integer.
-     *  Applicable to the following VRs: SS.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: SS.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -766,8 +790,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of signed 16-bit integers.
-     *  Applicable to the following VRs: SS.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: SS.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -780,8 +804,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an unsigned 32-bit integer.
-     *  Applicable to the following VRs: OL, UL.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: OL, UL.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -794,8 +818,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of unsigned 32-bit integers.
-     *  Applicable to the following VRs: OL, UL.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: OL, UL.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -808,8 +832,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a signed 32-bit integer.
-     *  Applicable to the following VRs: IS, SL.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: IS, SL.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -822,8 +846,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of signed 32-bit integers.
-     *  Applicable to the following VRs: SL.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: SL.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -836,8 +860,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an unsigned 64-bit integer.
-     *  Applicable to the following VRs: OV, UV.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: OV, UV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -850,8 +874,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of unsigned 64-bit integers.
-     *  Applicable to the following VRs: OV, UV.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: OV, UV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -864,8 +888,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a signed 64-bit integer.
-     *  Applicable to the following VRs: SV.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: SV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -878,8 +902,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                  const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of signed 64-bit integers.
-     *  Applicable to the following VRs: SV.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: SV.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -892,8 +916,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                       const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a (signed) long integer.
-     *  Applicable to the following VRs: IS, OL, SL, SS, UL, US.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: IS, OL, SL, SS, UL, US.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -906,8 +930,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                   const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a 32-bit floating point.
-     *  Applicable to the following VRs: FL, OF.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: FL, OF.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -920,8 +944,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                   const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of 32-bit floating point values.
-     *  Applicable to the following VRs: FL, OF.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: FL, OF.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -934,8 +958,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                        const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as a 64-bit floating point.
-     *  Applicable to the following VRs: DS, FD, OD.
      *  The result variable 'value' is automatically set to zero if an error occurs.
+     *  @note Applicable to the following VRs: DS, FD, OD.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the element value is stored
      *  @param pos index of the value in case of multi-valued elements (0..vm-1)
@@ -948,8 +972,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                   const OFBool searchIntoSub = OFFalse);
 
     /** find element and get value as an array of 64-bit floating point values.
-     *  Applicable to the following VRs: FD, OD.
      *  The result variable 'value' is automatically set to NULL if an error occurs.
+     *  @note Applicable to the following VRs: FD, OD.
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param value variable in which the reference to the element value is stored
      *  @param count stores number of items in the result array (if not NULL)
@@ -962,9 +986,9 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                        const OFBool searchIntoSub = OFFalse);
 
     /** looks up and returns a given sequence.
-     *  Applicable to the following VRs: SQ, (pixelSQ).
      *  The result variable 'sequence' is automatically set to NULL if an error occurs
      *  (e.g. if 'seqTagKey' does not refer to a sequence attribute).
+     *  @note Applicable to the following VRs: SQ, (pixelSQ).
      *  @param seqTagKey DICOM tag specifying the sequence attribute to be searched for
      *  @param sequence variable in which the reference to (or copy of) the sequence is stored
      *  @param searchIntoSub flag indicating whether to search into sub-sequences or not
@@ -980,8 +1004,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  to NULL and returns EC_TagNotFound (specified sequence does not exist) or
      *  EC_IllegalParameter (specified item does not exist). Only the top-most level of
      *  the dataset/item is examined (i.e. no deep-search is performed).
-     *  Applicable to the following VRs: SQ, (pixelSQ).
      *  Please note that an instance of the DcmPixelItem class cannot be retrieved.
+     *  @note Applicable to the following VRs: SQ, (pixelSQ).
      *  @param seqTagKey DICOM tag specifying the sequence attribute to be searched for
      *  @param item variable in which the reference to (or copy of) the item is stored
      *  @param itemNum number of the item to be searched for (0..n-1, -1 for last)
@@ -1000,9 +1024,9 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  If either the sequence or the item do not exist, they are created. If necessary,
      *  multiple empty items are inserted. Only the top-most level of the dataset/item
      *  is examined (i.e. no deep-search is performed).
-     *  Applicable to the following VRs: SQ, (pixelSQ).
      *  Please note that an instance of the DcmPixelItem class cannot be retrieved or
      *  created.
+     *  @note Applicable to the following VRs: SQ, (pixelSQ).
      *  @param seqTag DICOM tag specifying the sequence attribute to be searched for
      *    (or to be created)
      *  @param item variable in which the reference to the sequence item is stored
@@ -1021,7 +1045,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  of items). Empty elements are also copied. However, if the given tag is not
      *  found in the current dataset, EC_TagNotFound is returned and the destination
      *  dataset remains unchanged.
-     *  Applicable to all DICOM value representations (VR).
+     *  @note Applicable to all DICOM value representations (VR).
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param destItem destination dataset to which the copied element is inserted
      *  @param replaceOld flag indicating whether to replace an existing element or not
@@ -1032,7 +1056,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                            const OFBool replaceOld = OFTrue);
 
     /** find element, remove it from the dataset and free the associated memory.
-     *  Applicable to all DICOM value representations (VR).
+     *  @note Applicable to all DICOM value representations (VR).
      *  @param tagKey DICOM tag specifying the attribute to be searched for
      *  @param allOccurrences flag indicating whether to delete all occurrences of the
      *    attribute tag or the first one only (implies 'searchIntoSub' to be true)
@@ -1044,7 +1068,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                      const OFBool searchIntoSub = OFFalse);
 
     /** looks up the given sequence in the current dataset and deletes the given item.
-     *  Applicable to the following VRs: SQ, (pixelSQ).
+     *  @note Applicable to the following VRs: SQ, (pixelSQ).
      *  @param seqTagKey DICOM tag specifying the sequence attribute to be searched for
      *  @param itemNum number of the item to be deleted (0..n-1, -1 for last)
      *  @return EC_Normal upon success, an error otherwise.
@@ -1056,8 +1080,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
     /* --- putAndInsert functions: put value and insert new element --- */
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB,
+     *    OD, OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value string value to be set for the new element (might be empty or NULL).  The format
      *    of the string value is specified by the putString() method of the corresponding VR class.
@@ -1069,10 +1093,10 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  Please note that since the length of the string has to be specified explicitly, the string
      *  can contain more than one NULL byte.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB,
+     *    OD, OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value string value to be set for the new element (might be empty or NULL).  The format
      *    of the string value is specified by the putString() method of the corresponding VR class.
@@ -1086,8 +1110,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB,
+     *    OD, OF, OL, OV, OW, PN, SH, SL, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value string value to be set for the new element (might be empty).  The format of the
      *    string value is specified by the putOFStringArray() method of the corresponding VR class.
@@ -1099,7 +1123,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                           const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: OB, ox (polymorph OB/OW or pixel data).
+     *  @note Applicable to the following VRs: OB, ox (polymorph OB/OW), px (pixel data).
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element (might be NULL)
      *  @param count number of values (= bytes in this case) to be copied from 'value'
@@ -1112,7 +1136,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                        const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: US, xs (US or SS).
+     *  @note Applicable to the following VRs: US, xs (US or SS).
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1126,7 +1150,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: AT, OW, US, ox (polymorph OB/OW or pixel data), xs (US or SS).
+     *  @note Applicable to the following VRs: AT, OW, US, ox (polymorph OB/OW), px (pixel data),
+     *    xs (US or SS).
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element (might be NULL)
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1139,7 +1164,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                         const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: SS, xs (US or SS).
+     *  @note Applicable to the following VRs: SS, xs (US or SS).
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1153,7 +1178,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: SS, xs (US or SS).
+     *  @note Applicable to the following VRs: SS, xs (US or SS).
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1166,7 +1191,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                         const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: OL, UL.
+     *  @note Applicable to the following VRs: OL, UL.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1180,7 +1205,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: OL, UL.
+     *  @note Applicable to the following VRs: OL, UL.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1193,7 +1218,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                        const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: SL.
+     *  @note Applicable to the following VRs: SL.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1207,7 +1232,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                    const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: SL.
+     *  @note Applicable to the following VRs: SL.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1220,7 +1245,61 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                         const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: FL, OF.
+     *  @note Applicable to the following VRs: OV, UV.
+     *  @param tag DICOM tag specifying the attribute to be created
+     *  @param value value to be set for the new element
+     *  @param pos index of the value to be set (0..vm). A value can be appended to
+     *    the end of or inserted within the existing value field.
+     *  @param replaceOld flag indicating whether to replace an existing element or not
+     *  @return EC_Normal upon success, an error code otherwise.
+     */
+    OFCondition putAndInsertUint64(const DcmTag &tag,
+                                   const Uint64 value,
+                                   const unsigned long pos = 0,
+                                   const OFBool replaceOld = OFTrue);
+
+    /** create a new element, put specified value to it and insert the element into the dataset/item.
+     *  @note Applicable to the following VRs: OV, UV.
+     *  @param tag DICOM tag specifying the attribute to be created
+     *  @param value value to be set for the new element
+     *  @param count number of values (not bytes!) to be copied from 'value'
+     *  @param replaceOld flag indicating whether to replace an existing element or not
+     *  @return EC_Normal upon success, an error code otherwise.
+     */
+    OFCondition putAndInsertUint64Array(const DcmTag &tag,
+                                       const Uint64 *value,
+                                       const unsigned long count,
+                                       const OFBool replaceOld = OFTrue);
+
+    /** create a new element, put specified value to it and insert the element into the dataset/item.
+     *  @note Applicable to the following VRs: SV.
+     *  @param tag DICOM tag specifying the attribute to be created
+     *  @param value value to be set for the new element
+     *  @param pos index of the value to be set (0..vm). A value can be appended to
+     *    the end of or inserted within the existing value field.
+     *  @param replaceOld flag indicating whether to replace an existing element or not
+     *  @return EC_Normal upon success, an error code otherwise.
+     */
+    OFCondition putAndInsertSint64(const DcmTag &tag,
+                                   const Sint64 value,
+                                   const unsigned long pos = 0,
+                                   const OFBool replaceOld = OFTrue);
+
+    /** create a new element, put specified value to it and insert the element into the dataset/item.
+     *  @note Applicable to the following VRs: SV.
+     *  @param tag DICOM tag specifying the attribute to be created
+     *  @param value value to be set for the new element
+     *  @param count number of values (not bytes!) to be copied from 'value'
+     *  @param replaceOld flag indicating whether to replace an existing element or not
+     *  @return EC_Normal upon success, an error code otherwise.
+     */
+    OFCondition putAndInsertSint64Array(const DcmTag &tag,
+                                        const Sint64 *value,
+                                        const unsigned long count,
+                                        const OFBool replaceOld = OFTrue);
+
+    /** create a new element, put specified value to it and insert the element into the dataset/item.
+     *  @note Applicable to the following VRs: FL, OF.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1234,7 +1313,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                     const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: FL, OF.
+     *  @note Applicable to the following VRs: FL, OF.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1247,7 +1326,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                          const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: DS, FD, OD
+     *  @note Applicable to the following VRs: DS, FD, OD
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1261,7 +1340,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                     const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: FD, OD.
+     *  @note Applicable to the following VRs: FD, OD.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param count number of values (not bytes!) to be copied from 'value'
@@ -1274,7 +1353,7 @@ class DCMTK_DCMDATA_EXPORT DcmItem
                                          const OFBool replaceOld = OFTrue);
 
     /** create a new element, put specified value to it and insert the element into the dataset/item.
-     *  Applicable to the following VRs: AT.
+     *  @note Applicable to the following VRs: AT.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param value value to be set for the new element
      *  @param pos index of the value to be set (0..vm). A value can be appended to
@@ -1290,8 +1369,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
     /* --- insertXXX functions: insert new element --- */
 
     /** create a new element (with no value) and insert it into the dataset/item.
-     *  Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, OB, OD, OF,
-     *  OL, OV, OW, PN, SH, SL, SQ, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
+     *  @note Applicable to the following VRs: AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT,
+     *    OB, OD, OF, OL, OV, OW, PN, SH, SL, SQ, SS, ST, SV, TM, UC, UI, UL, UR, US, UT, UV.
      *  @param tag DICOM tag specifying the attribute to be created
      *  @param replaceOld flag indicating whether to replace an existing element or not
      *  @return EC_Normal upon success, an error code otherwise.
@@ -1303,8 +1382,8 @@ class DCMTK_DCMDATA_EXPORT DcmItem
      *  If the sequence does not exist, it is created. If necessary, multiple empty items
      *  are inserted before the specified item position. Only the top-most level of the
      *  dataset/item is examined (i.e. no deep-search is performed).
-     *  Applicable to the following VRs: SQ, (pixelSQ).
      *  Please note that an instance of the DcmPixelItem class cannot be inserted.
+     *  @note Applicable to the following VRs: SQ, (pixelSQ).
      *  @param seqTag DICOM tag specifying the sequence attribute to be searched for
      *    (or to be created)
      *  @param item item to be inserted into the sequence, must not be contained in this
@@ -1443,15 +1522,6 @@ class DCMTK_DCMDATA_EXPORT DcmItem
     OFBool checkAndUpdateVR(DcmItem &item,
                             DcmTag &tag);
 
-    /** update the SpecificCharacterSet (0008,0005) element depending on the given
-     *  parameters. The current value of this element is either replaced or a new
-     *  element is inserted or the existing element is deleted.
-     *  @param status error status of previous operations (might also be updated)
-     *  @param converter character set converter used to convert element values
-     */
-    void updateSpecificCharacterSet(OFCondition &status,
-                                    const DcmSpecificCharacterSet &converter);
-
     /** creates new DICOM element from given attribute tag.
      *  Helper function used by DICOM parser (friend of this class) and thus
      *  hidden from the public interface. DcmItem's readSubElement() uses
index 47818159ceb09e153254823b1b9edb334491ee4a..891443c21751f929848149e02deeac06167ecaea 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *
-*  Copyright (C) 2017-2022, OFFIS e.V.
+*  Copyright (C) 2017-2025, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were developed by
 #define DCJSON_H
 
 #include "dcmtk/config/osconfig.h" // make sure OS specific configuration is included first
-
 #include "dcmtk/ofstd/ofdefine.h"
 #include "dcmtk/ofstd/ofstring.h"
-
 #include "dcmtk/dcmdata/dctagkey.h"
 
+class OFCondition;
+
 /** Class for handling JSON format options.
  *  Base class to implement custom formatting.
  *  Purpose:
@@ -88,9 +88,9 @@ public:
    };
 
     /** A class to create small proxy objects that ease indention handling.
-     *  Each Indention object only contains a reference to the DcmJsonFormat object
-     *  that created it and its only purpose is to call the respective methods
-     *  of that object when one of its overloaded operators is used.
+     *  Each Indention object only contains a reference to the DcmJsonFormat
+     *  object that created it and its only purpose is to call the respective
+     *  methods of that object when one of its overloaded operators is used.
      */
     class Indention
     {
@@ -214,14 +214,17 @@ public:
                                    OFString &value);
 
     /** Constructor
-     *  @param printMetaInfo parameter that defines if meta information should be written
+     *  @param printMetaInfo parameter that defines if meta information should
+     *    be written
      */
     inline DcmJsonFormat(const OFBool printMetaInfo)
     : printMetaheaderInformation(printMetaInfo)
     , enableJsonExtension(OFFalse)
     , numStringPolicy(NSP_auto)
+    , minBulkDataSize(-1)
+    , bulkDataURIPrefix()
+    , bulkDataDirectory()
     {
-
     }
 
     /** Virtual destructor, does nothing
@@ -238,7 +241,8 @@ public:
      */
     virtual OFString space() = 0;
 
-    /** Method to return an indention proxy object for increasing, decreasing or printing indention
+    /** Method to return an indention proxy object for increasing, decreasing or
+     *  printing indention
      *  @return an indention proxy object.
      */
     inline Indention indent()
@@ -250,37 +254,20 @@ public:
      *  Override this function to implement bulk data URI output.
      *  @param tag the tag of the attribute being printed, for letting
      *    the implementation decide how to handle it.
-     *  @param uri the resulting URI to output.
+     *  @param len the length of the attribute value, in bytes
      *  @return OFTrue if yes, OFFalse if no.
-     *  @details
-     *  <h3>Usage Example:</h3>
-     *  @code{.cpp}
-     *  struct BulkDataURIJsonFormat : DcmJsonFormatPretty
-     *  {
-     *    CustomJsonFormat(const OFBool printMetaInfo = OFTrue,
-     *                     ... bulkDataURIDatabase)
-     *    : DcmJsonFormatPretty(printMetaInfo)
-     *    , TheDatabase(bulkDataURIDatabase)
-     *    {
-     *
-     *    }
-     *
-     *    virtual OFBool asBulkDataURI(const DcmTagKey& tag, OFString& uri)
-     *    {
-     *      ... result = TheDatabase.findBulkDataFor(tag);
-     *      if (result.found())
-     *      {
-     *        uri = result.uri();
-     *        return OFTrue;
-     *      }
-     *      return OFFalse;
-     *    }
-     *
-     *    ... TheDatabase;
-     *  }
-     *  @endcode
      */
-    virtual OFBool asBulkDataURI(const DcmTagKey& tag, OFString& uri);
+    virtual OFBool asBulkDataURI(const DcmTagKey& tag, Uint32 len) const;
+
+    /** return path of bulk data directory
+     *  @param directory path returned in this parameter
+     */
+    virtual void getBulkDataDirectory(OFString& directory) const;
+
+    /** return the current bulk data URI prefix
+     *  @return prefix current bulk data URI prefix returned in this parameter
+     */
+    virtual void getBulkDataURIPrefix(OFString& prefix) const;
 
     /** Print the Prefix which for JSON Values needed
      *  with indention and newlines as in the format Variable given.
@@ -367,6 +354,51 @@ public:
      */
     const OFBool printMetaheaderInformation;
 
+    /** set the minimum size of binary attributes stored as bulk data.
+     *  @param min_bulk_size minimum bulk data size in kBytes, negative number for no bulk data
+     */
+    virtual void setMinBulkSize(ssize_t min_bulk_size);
+
+    /** set the prefix for URIs generated for bulk data
+     *  @param bulk_uri_prefix URI prefix string
+     */
+    virtual void setBulkURIPrefix(const char *bulk_uri_prefix);
+
+    /** set the directory to which bulk data files should be written
+     *  @param bulk_dir directory for bulk data files, must exist and be writable
+     */
+    virtual void setBulkDir(const char *bulk_dir);
+
+    /** write an attribute as BulkDataURI.
+     *  @param out output stream
+     *  @param tagkey tag key of the attribute
+     *  @param len length of the attribute value
+     *  @param byteValues pointer to the raw attribute value in little endian byte order
+     *  @param extension file name extension
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition writeBulkData(
+        STD_NAMESPACE ostream &out,
+        const DcmTagKey& tagkey,
+        Uint32 len,
+        Uint8 *byteValues,
+        const char *extension = ".bin");
+
+    /** write a binary attribute either as InlineBinary or as BulkDataURI.
+     *  @param out output stream
+     *  @param tagkey tag key of the attribute
+     *  @param len length of the attribute value
+     *  @param byteValues pointer to the raw attribute value in little endian byte order
+     *  @param extension file name extension
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition writeBinaryAttribute(
+        STD_NAMESPACE ostream &out,
+        const DcmTagKey& tagkey,
+        Uint32 len,
+        Uint8 *byteValues,
+        const char *extension = ".bin");
+
 protected:
     /** Indent to the specific level.
      *  @param out output stream to which the indention is written.
@@ -394,6 +426,22 @@ private:
      *  as number or string. Default is NSP_auto.
      */
     NumStringPolicy numStringPolicy;
+
+    /** minimum size of binary attributes to be written as bulk data,
+     *  in kBytes. A negative value means that no bulk data is written.
+     */
+    ssize_t minBulkDataSize;
+
+    /** prefix for bulk data URIs to be generated. The filename will
+     *  be appended to this prefix.
+     */
+    OFString bulkDataURIPrefix;
+
+    /** directory to which files for bulk data will be written.
+     *  Must exist and be writable.
+     */
+    OFString bulkDataDirectory;
+
 };
 
 
diff --git a/dcmdata/include/dcmtk/dcmdata/dcjsonrd.h b/dcmdata/include/dcmtk/dcmdata/dcjsonrd.h
new file mode 100644 (file)
index 0000000..85c125a
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Tingyan Xu, Marco Eichelberg
+ *
+ *  Purpose: Class for converting JSON DICOM documents to binary DICOM files
+ *
+ */
+
+#ifndef DCJSONRD_H
+#define DCJSONRD_H
+
+class OFCondition;
+
+#include "dcmtk/config/osconfig.h"      /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/oftypes.h"        /* for OFBool */
+#include "dcmtk/dcmdata/dcdefine.h"     /* for DCMTK_DCMDATA_EXPORT */
+#include "dcmtk/dcmdata/dcxfer.h"       /* for E_TransferSyntax */
+#include "dcmtk/ofstd/oflist.h"         /* for OFList */
+
+#define JSMN_HEADER
+#include "dcmtk/ofstd/ofjsmn.h"         /* for JSMN declarations  */
+
+typedef jsmn_parser OFJsmnParser;
+typedef jsmntok_t OFJsmnToken;
+typedef OFJsmnToken *OFJsmnTokenPtr;
+
+class DcmFileFormat;
+class DcmElement;
+class DcmTagKey;
+class DcmTag;
+class DcmSequenceOfItems;
+class DcmItem;
+
+
+/** input stream that reads from standard input
+ */
+class DCMTK_DCMDATA_EXPORT DcmJSONReader
+{
+public:
+  /// constructor
+  DcmJSONReader();
+
+  /// destructor
+  virtual ~DcmJSONReader();
+
+  /// delete all internal buffers, but keep policy settings
+  virtual void clear();
+
+  /** read a JSON file and store the content in this object
+   *  @param ifname name of the JSON file to be read
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition readJSONFile(const char *ifname);
+
+  /** read a JSON dataset from stdin and store the content in this object
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition readJSONFromStdin();
+
+  /** set the "ignore bulk data URI" policy
+   *  @param value new policy, true = ignore bulk data URIs
+   */
+  virtual void setIgnoreBulkdataURIPolicy(OFBool value) { ignoreBulkdataURIPolicy_ = value; }
+
+  /** set the "stop on error" policy
+   *  @param value new policy, true = stop when encountering a parse error
+   */
+  virtual void setStopOnErrorPolicy(OFBool value) { stopOnErrorPolicy_ = value; }
+
+  /** set the "ignore meta info" policy
+   *  @param value new policy, true = ignore meta info elements in JSON dataset
+   */
+  virtual void setIgnoreMetaInfoPolicy(OFBool value) { ignoreMetaInfoPolicy_ = value; }
+
+  /** set the array handling policy
+   *  @param value new policy
+   *    - -1: reject arrays with more than one dataset
+   *    - 0: store arrays with multiple datasets as a private sequence
+   *    - n > 0: select dataset n from the array, ignore all others   */
+  virtual void setArrayHandlingPolicy(signed long value) { arrayHandlingPolicy_ = value; }
+
+  /** set the transfer syntax for the dataset
+   *  @param value transfer syntax
+   */
+  virtual void setTransferSyntax(E_TransferSyntax value) { xferSyntax_ = value; }
+
+  /** set the transfer syntax for the dataset
+   *  @param value transfer syntax
+   */
+  virtual E_TransferSyntax getTransferSyntax() const { return xferSyntax_; }
+
+  /** parse the JSON file with the given filename
+   *  @param fileformat DcmFileFormat instance to be populated with the parsed JSON content
+   *  @param ifname name of the JSON file to be read
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition readAndConvertJSONFile(
+      DcmFileFormat& fileformat,
+      const char *ifname);
+
+  /** dump the token array produced by the JSMN parser to stderr
+   */
+  virtual OFCondition dumpJSONTokenArray();
+
+  /** check if the given URI is a file URI
+   *  @param uri URI to check
+   *  @return true if the URI is a file URI
+   */
+  virtual OFBool isFileURI(const OFString& uri) const;
+
+  /** check if the given URI is a http: or https: URI
+   *  @param uri URI to check
+   *  @return true if the URI is a http: or https: URI
+   */
+  virtual OFBool isHttpURI(const OFString& uri) const;
+
+  /** URL decode the given URI, i.e. replace all instances of '%xx' with the hex number xx
+   *  by the corresponding byte.
+   *  @param uri URI string, will be modified by this method.
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition urlDecode(OFString& uri) const;
+
+  /** convert a file URI to a file path in the local filesystem
+   *  @param uri the file URI to convert
+   *  @param filepath the file path is returned in this parameter
+   *  @param offset the byte offset within the file is returned in this parameter
+   *  @param length the number of bytes to read from the file is returned in this parameter, 0 means 'unlimited'
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition fileURItoPath(const OFString& uri, OFString& filepath, size_t& offset, size_t& length) const;
+
+  /** normalize a file path into an absolute path without symbolic links.
+   *  On Windows, the long version of directory and file names will be generated
+   *  and converted to uppercase, since the Win32 file API uses case insensitive filenames
+   *  @param filepath_in the file path to be normalized
+   *  @param filepath_out the normalized file path is returned in this parameter.
+   *    This parameter must not reference the same string as filepath_in.
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition normalizePath(const OFString& filepath_in, OFString& filepath_out) const;
+
+  /** add a path from which bulk data files may be read if referenced by a
+   *  file BulkdataURI. The path will be normalized before being stored.
+   *  All subdirectories of the given directory will also be accepted a valid paths.
+   *  @param dirpath the directory path that is acceptable for bulk data
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition addPermittedBulkdataPath(const OFString& dirpath);
+
+  /** check if the given normalized path (which may include a filename)
+   *  is in the list of permitted bulk data paths as defined by calls to
+   *  addPermittedBulkdataPath().
+   *  @param filepath the file path to be checked
+   *  @return OFTrue if path is permitted, OFFalse otherwise
+   */
+  virtual OFBool bulkdataPathPermitted(const OFString& filepath) const;
+
+  /** load bulk data from file and insert it into the given element
+   *  @param element element into which the value will be inserted
+   *  @param filepath path to the bulk data file
+   *  @param offset offset in bytes within the file from where to start reading
+   *  @param length number of bytes to read from file, 0 for the entire file from the given offset
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition loadBulkdataFile(
+      DcmElement& element,
+      const OFString& filepath,
+      size_t offset,
+      size_t length);
+
+private:
+
+  /// null terminated character string containing the entire JSON dataset
+  char *jsonDataset_;
+
+  /// size of jsonDataset_ in bytes, not including the terminating null byte
+  size_t jsonDatasetLen_;
+
+  /// array of parsed JSON tokens
+  OFJsmnTokenPtr tokenArray_;
+
+  /// number of tokens in tokenArray_
+  int tokenNumber_;
+
+  /// policy for handling bulk data URIs (true = ignore)
+  OFBool ignoreBulkdataURIPolicy_;
+
+  /// policy for error handling (false = ignore)
+  OFBool stopOnErrorPolicy_;
+
+  /// policy for handling meta info elements in the JSON dataset (true = ignore)
+  OFBool ignoreMetaInfoPolicy_;
+
+  /** policy for handling arrays of multiple datasets.
+   *    - -1: reject arrays with more than one dataset
+   *    - 0: store arrays with multiple datasets as a private sequence
+   *    - n > 0: select dataset n from the array, ignore all others
+   */
+  signed long arrayHandlingPolicy_;
+
+  /// transfer syntax of the dataset, default: LittleEndianExplicit
+  E_TransferSyntax xferSyntax_;
+
+  /// list of directories to which file URIs may point
+  OFList<OFString> permittedBulkdataDirs_;
+
+  /** calculate the required number of tokens for the JSON dataset
+   *  and allocate the token array accordingly
+   */
+  OFCondition reserveTokens();
+
+  /** parse the JSON dataset that has be read into the buffer
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parseJSON();
+
+  /// private unimplemented copy constructor
+  DcmJSONReader(const DcmJSONReader&);
+
+  /// private unimplemented copy assignment operator
+  DcmJSONReader& operator=(const DcmJSONReader&);
+
+  /** helper function to retrieve the content of the token.
+   *  There is no check on boundaries!
+   *  @param value the result string
+   *  @param t token pointer
+   */
+  void getTokenContent(
+      OFString& value,
+      OFJsmnTokenPtr t);
+
+  /** create DICOM element using the given tag and VR
+   *  @param newElem pointer to newly created DICOM element returned in this parameter
+   *  @param dcmTag attribute tag
+   *  @param vr the string representation of the VR (if present)
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition createElement(
+      DcmElement *& newElem,
+      DcmTag& dcmTag,
+      const OFString& vr);
+
+  /** extract DICOM tag from the given string
+   *  @param keyToken token containing the string representation of the tag in form of "ggggeeee"
+   *  @param tagkey stores the extracted DICOM tag
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition extractTag(
+      OFJsmnTokenPtr keyToken,
+      DcmTagKey& tagkey);
+
+  /** helper function processing escaped characters in JSON strings
+   *  @param value containing the string. The string will be changed
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition processJSONEscapeCharacters(OFString& value);
+
+  /** parse the dataset part of an XML file containing a DICOM file or a DICOM dataset.
+   *  @param dataset dataset stored in this parameter
+   *  @param metaheader metaheader stored in this parameter
+   *  @param current pointer to current JSMN Token
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parseDataSet(
+      DcmItem* dataset,
+      DcmItem* metaheader,
+      OFJsmnTokenPtr& current);
+
+  /** parse a DICOM sequence
+   *  @param sequence DICOM Sequence
+   *  @param current pointer to current token in the tokenArray
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parseSequence(
+      DcmSequenceOfItems& sequence,
+      OFJsmnTokenPtr& current);
+
+  /** parse a DICOM element that is not a sequence
+   *  @param dataset dataset stored in this parameter
+   *  @param metaheader metaheader stored in this parameter
+   *  @param current pointer to current JSMN Token
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parseElement(
+      DcmItem* dataset,
+      DcmItem* metaheader,
+      OFJsmnTokenPtr& current);
+
+  /** parse a value array from JSON to DICOM
+   *  @param newElem Pointer to element where the value should be stored
+   *  @param current pointer to current token in the tokenArray
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parseElementValueArray(
+      DcmElement*& newElem,
+      OFJsmnTokenPtr& current);
+
+  /** parse a person name (PN value)
+   *  @param value string containing the PN DICOM value
+   *  @param current pointer to current token in the tokenArray
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition parsePersonName(
+      OFString& value,
+      OFJsmnTokenPtr& current);
+
+  /** store decoded inline binary value in a DICOM element
+   *  @param element element into which the value will be inserted
+   *  @param data buffer containing the inline binary data
+   *  @param length of the buffer
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition storeInlineBinaryValue(
+      DcmElement& element,
+      Uint8 *data,
+      size_t length);
+
+  /** store loaded bulk data value in a DICOM element
+   *  @param element element into which the value will be inserted
+   *  @param data buffer containing the bulk data
+   *  @param length of the buffer
+   *  @return EC_Normal upon success, an error code otherwise
+   */
+  virtual OFCondition storeBulkValue(
+    DcmElement& element,
+    Uint8 *data,
+    size_t length);
+
+};
+
+#endif
index 7a632fa36b90e44a642bdc1a40fe67fdcdeb2cf2..a5bdebed41eeb5f252fc2dd172794dd6f334671c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2021, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -34,20 +34,20 @@ const unsigned long DCM_EndOfListIndex = OFstatic_cast(unsigned long, -1L);
 
 /** helper class maintaining an entry in a DcmList double-linked list
  */
-class DCMTK_DCMDATA_EXPORT DcmListNode 
+class DCMTK_DCMDATA_EXPORT DcmListNode
 {
 
 public:
     /** constructor
      *  @param obj object to be maintained by this list node
      */
-    DcmListNode( DcmObject *obj );
+    DcmListNode(DcmObject *obj);
 
     /// destructor
     ~DcmListNode();
 
     /// return pointer to object maintained by this list node
-    inline DcmObject *value() { return objNodeValue; } 
+    inline DcmObject *value() { return objNodeValue; }
 
 private:
     friend class DcmList;
@@ -61,10 +61,10 @@ private:
     /// pointer to DcmObject instance maintained by this list entry
     DcmObject *objNodeValue;
 
-    /// private undefined copy constructor 
+    /// private undefined copy constructor
     DcmListNode(const DcmListNode &);
 
-    /// private undefined copy assignment operator 
+    /// private undefined copy assignment operator
     DcmListNode &operator=(const DcmListNode &);
 
 };
@@ -89,10 +89,10 @@ typedef enum
 } E_ListPos;
 
 /** double-linked list class that maintains pointers to DcmObject instances.
- *  The remove operation does not delete the object pointed to, however,
- *  the destructor will delete all elements pointed to
+ *  The remove operation does not delete the object pointed to, however, the
+ *  destructor will delete all elements the list points to.
  */
-class DCMTK_DCMDATA_EXPORT DcmList 
+class DCMTK_DCMDATA_EXPORT DcmList
 {
 public:
     /// constructor
@@ -103,23 +103,23 @@ public:
 
     /** insert object at end of list
      *  @param obj pointer to object
-     *  @return pointer to object
+     *  @return pointer to object, or NULL if object cannot be inserted
      */
-    DcmObject *append(  DcmObject *obj );
+    DcmObject *append(DcmObject *obj);
 
     /** insert object at start of list
      *  @param obj pointer to object
-     *  @return pointer to object
+     *  @return pointer to object, or NULL if object cannot be inserted
      */
-    DcmObject *prepend( DcmObject *obj );
+    DcmObject *prepend(DcmObject *obj);
 
     /** insert object relative to current position and indicator
      *  @param obj pointer to object
      *  @param pos position indicator
-     *  @return pointer to object
+     *  @return pointer to object, or NULL if object cannot be inserted
      */
-    DcmObject *insert(  DcmObject *obj,
-                        E_ListPos pos = ELP_next );
+    DcmObject *insert(DcmObject *obj,
+                      const E_ListPos pos = ELP_next);
 
     /** remove current entry from list, return element
      *  @return pointer to removed element, which is not deleted
@@ -130,36 +130,36 @@ public:
      *  @param pos position indicator
      *  @return pointer to object
      */
-    DcmObject *get(     E_ListPos pos = ELP_atpos );
+    DcmObject *get(const E_ListPos pos = ELP_atpos);
 
     /** seek within element in list to given position
      *  (i.e. set current element to given position)
      *  @param pos position indicator
      *  @return pointer to new current object
      */
-    DcmObject *seek(    E_ListPos pos = ELP_next );
+    DcmObject *seek(const E_ListPos pos = ELP_next);
 
     /** seek within element in list to given element index
      *  (i.e. set current element to given index)
      *  @param absolute_position position index < card()
      *  @return pointer to new current object
      */
-    DcmObject *seek_to(unsigned long absolute_position);
+    DcmObject *seek_to(const unsigned long absolute_position);
 
-    /** Remove and delete all elements from list. Thus, the 
-     *  elements' memory is also freed by this operation. The list
-     *  is empty after calling this function.
-     */  
+    /** remove and delete all elements from list. Thus, the elements' memory
+     *  is also freed by this operation. The list is empty after calling this
+     *  function.
+     */
     void deleteAllElements();
 
     /// return cardinality of list
     inline unsigned long card() const { return cardinality; }
 
     /// return true if list is empty, false otherwise
-    inline OFBool empty(void) const { return firstNode == NULL; }
+    inline OFBool empty() const { return firstNode == NULL; }
 
     /// return true if current node exists, false otherwise
-    inline OFBool valid(void) const { return currentNode != NULL; }
+    inline OFBool valid() const { return currentNode != NULL; }
 
 private:
     /// pointer to first node in list
@@ -171,10 +171,15 @@ private:
     /// pointer to current node in list
     DcmListNode *currentNode;
 
+    /// current position in list.
+    /// The position is maintained in order to avoid O(n) lookup
+    /// when essentially iterating the elements using seek_to().
+    unsigned long currentPosition;
+
     /// number of elements in list
     unsigned long cardinality;
-    /// private undefined copy constructor 
+
+    /// private undefined copy constructor
     DcmList &operator=(const DcmList &);
 
     /** private undefined copy assignment operator
index 8d7766a3466481ac2e91eac53c67d5fcaef607fb..980cf179d690a81b0552331f7312d283e255092e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -197,6 +197,12 @@ class DCMTK_DCMDATA_EXPORT DcmMetaInfo
                                  const E_GrpLenEncoding groupLength = EGL_noChange,
                                  const Uint32 maxReadLength = DCM_MaxReadLength);
 
+    /** access the file preamble after reading a DICOM file.
+     *  @return pointer to a 132-byte array containing the DICOM file preamble
+     *    (i.e. the unused first 128 bytes of a DICOM file) and the magic word
+     *    ("DICM"). If no DICOM fileformat was loaded, array will be zeroed.
+     */
+    virtual const char *getPreamble() const;
 
   private:
 
index 352ea0adbf321ebeca41a479434b986e7ef7e6db..ec4b7f1758525fc59b39a51aebce41b6b786f540 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2003-2024, OFFIS e.V.
+ *  Copyright (C) 2003-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -29,6 +29,7 @@
 
 #include "dcmtk/ofstd/ofcond.h"
 #include "dcmtk/ofstd/oftypes.h"
+#include "dcmtk/ofstd/ofdiag.h"
 #include "dcmtk/dcmdata/dcxfer.h"
 
 #ifdef __ibmxl__
@@ -46,7 +47,12 @@ typedef xmlNode *xmlNodePtr;
 typedef struct _xmlDoc xmlDoc;
 typedef xmlDoc *xmlDocPtr;
 
+// MacOS 15.5 defines some Clang specific pragmas in libxml header files.
+// Suppress warnings caused by these pragmas when compiling with GCC.
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC
 #include <libxml/xmlstring.h>
+#include DCMTK_DIAGNOSTIC_POP
 
 class DcmElement;
 class DcmItem;
index 057af8ca3471566a11f84e6463f3bffd0ce477e6..d2417cb15bfd5476daad487a6489d468f1663f0d 100644 (file)
@@ -180,6 +180,7 @@ private:
     /// in write function: pointer to current pixel sequence
     DcmPixelSequence * pixelSeqForWrite;
 
+
     /** check if this element should be written unencapsulated, even though an
      *  encapsulated transfer syntax is used. In other words, this checks if
      *  this pixel data element is on the main level on the dataset or not.
@@ -694,6 +695,20 @@ public:
     virtual OFCondition getDecompressedColorModel(
         DcmItem *dataset,
         OFString &decompressedColorModel);
+
+   /** determines the effective value of BitsAllocated that a dataset will have
+     *  after decompression of an image with the given values for bitsAllocated
+     *  and bitsStored. This may differ from the bitsAllocated parameter for example
+     *  if that value is not a multiple of 8. Returns zero if an image with the
+     *  given parameters cannot be decoded.
+     *  @param bitsAllocated current value of Bits Allocated
+     *  @param bitsStored current value of Bits Stored
+     *  @return effective value of BitsAllocated, 0 if no decompression possible
+     */
+    virtual Uint16 decodedBitsAllocated(
+      Uint16 bitsAllocated,
+      Uint16 bitsStored) const;
+
 };
 
 #endif
index d7fd0d7111c9b60dded296459642ac1f6a35a810..07c6f719f9d9012d13b041548f4ac6d6074ed218 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -212,6 +212,14 @@ public:
     virtual OFCondition writeXML(STD_NAMESPACE ostream &out,
                                  const size_t flags = 0);
 
+    /** write object in JSON format to a stream
+     *  @param out output stream to which the JSON document is written
+     *  @param format used to format and customize the output
+     *  @return status, EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition writeJson(STD_NAMESPACE ostream &out,
+                                  DcmJsonFormat &format);
+
     /** special write method for creation of digital signatures
      *  @param outStream DICOM output stream
      *  @param oxfer output transfer syntax
index 77155b3238094fe81c1249b7e1679a8b55fed45f..a4354b0d9045b63fcb7b58f16cc7dff6e28ecd0f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2011, OFFIS e.V.
+ *  Copyright (C) 2002-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -163,6 +163,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
index 4e36cea1e3de933859e096653e674e3ddcca9e4e..398a8360fb7fb63fb06b7c6ddeec69a35969f133 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2020, OFFIS e.V.
+ *  Copyright (C) 2002-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -165,6 +165,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
index eee88e2372f8444471ae4eb8348f92e1478a7eb0..08330a35016c53a95d34f258cf2d470e687e2213 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2017, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -36,7 +36,7 @@ class DcmItem;
 
 /** A class for managing and converting between different DICOM character sets.
  *  The conversion relies on the OFCharacterEncoding class, which again relies
- *  on an underlying character encoding library (e.g. libiconv or ICU).
+ *  on an underlying character encoding library (e.g. oficonv or libiconv).
  *  @note Please note that a current limitation is that only a single value is
  *    allowed for the destination character set (i.e. no code extensions).  Of
  *    course, for the source character set, also multiple values are supported.
@@ -52,19 +52,20 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
 
     /** destructor
      */
-    ~DcmSpecificCharacterSet();
+    virtual ~DcmSpecificCharacterSet();
 
     /** clear the internal state.  This also forgets about the currently
      *  selected character sets, so selectCharacterSet() has to be called again
      *  before a string can be converted with convertString().
      */
-    void clear();
+    virtual void clear();
 
     /** query whether selectCharacterSet() has successfully been called for this
      *  object, i.e.\ whether convertString() may be called.
      *  @return OFTrue if selectCharacterSet() was successfully called before,
      *    OFFalse if not (or clear() has been called in the meantime).
      */
+    virtual
 #ifdef HAVE_CXX11
     explicit
 #endif
@@ -75,7 +76,7 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @return OFTrue if selectCharacterSet() must be called before using
      *    convertString(), OFFalse if it has already been called.
      */
-    OFBool operator!() const;
+    virtual OFBool operator!() const;
 
     /** get currently selected source DICOM character set(s).  Please note that
      *  the returned string can contain multiple values (defined terms separated
@@ -85,7 +86,7 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @return currently selected source DICOM character set(s) or an empty
      *    string if none is selected (identical to ASCII, which is the default)
      */
-    const OFString &getSourceCharacterSet() const;
+    virtual const OFString &getSourceCharacterSet() const;
 
     /** get currently selected destination DICOM character set.  Please note
      *  that the returned string, which contains a defined term, is always
@@ -93,7 +94,7 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @return currently selected destination DICOM character set or an empty
      *    string if none is selected (identical to ASCII, which is the default)
      */
-    const OFString &getDestinationCharacterSet() const;
+    virtual const OFString &getDestinationCharacterSet() const;
 
     /** get currently selected destination encoding, i.e.\ the name of the
      *  character set as used by the underlying character encoding library for
@@ -102,15 +103,15 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @return currently selected destination encoding or an empty string if
      *    none is selected
      */
-    const OFString &getDestinationEncoding() const;
+    virtual const OFString &getDestinationEncoding() const;
 
     /** @copydoc OFCharacterEncoding::getConversionFlags()
      */
-    unsigned getConversionFlags() const;
+    virtual unsigned getConversionFlags() const;
 
     /** @copydoc OFCharacterEncoding::setConversionFlags()
      */
-    OFCondition setConversionFlags(const unsigned flags);
+    virtual OFCondition setConversionFlags(const unsigned flags);
 
     /** select DICOM character sets for the input and output string, between
      *  which subsequent calls of convertString() convert.  The defined terms
@@ -133,8 +134,8 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                       default value is "ISO_IR 192" (Unicode in UTF-8).
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition selectCharacterSet(const OFString &fromCharset,
-                                   const OFString &toCharset = "ISO_IR 192");
+    virtual OFCondition selectCharacterSet(const OFString &fromCharset,
+                                           const OFString &toCharset = "ISO_IR 192");
 
     /** select DICOM character sets for the input and output string, between
      *  which subsequent calls of convertString() convert.  The source
@@ -160,12 +161,16 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                     value is "ISO_IR 192" (Unicode in UTF-8).
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition selectCharacterSet(DcmItem &dataset,
-                                   const OFString &toCharset = "ISO_IR 192");
+    virtual OFCondition selectCharacterSet(DcmItem &dataset,
+                                           const OFString &toCharset = "ISO_IR 192");
 
     /** convert the given string from the selected source character set(s) to
      *  the selected destination character set.  That means selectCharacterSet()
      *  has to be called prior to this method.
+     *  @note The conversion code does not perform a thorough validation of the
+     *    string.  For example, characters that are permitted in the source
+     *    character set but forbidden in DICOM (such as byte positions 0x80-0x9F
+     *    in ISO_IR 100) may be converted without warning or error.
      *  @param  fromString  input string to be converted (using the currently
      *                      selected source character set)
      *  @param  toString    reference to variable where the converted string
@@ -177,15 +182,19 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                      always regarded as delimiters (see DICOM PS 3.5).
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition convertString(const OFString &fromString,
-                              OFString &toString,
-                              const OFString &delimiters = "");
+    virtual OFCondition convertString(const OFString &fromString,
+                                      OFString &toString,
+                                      const OFString &delimiters = "");
 
     /** convert the given string from the selected source character set(s) to
      *  the selected destination character set.  That means selectCharacterSet()
      *  has to be called prior to this method.  Since the length of the input
      *  string has to be specified explicitly, the string can contain more than
      *  one NULL byte.
+     *  @note The conversion code does not perform a thorough validation of the
+     *    string.  For example, characters that are permitted in the source
+     *    character set but forbidden in DICOM (such as byte positions 0x80-0x9F
+     *    in ISO_IR 100) may be converted without warning or error.
      *  @param  fromString  input string to be converted (using the currently
      *                      selected character set)
      *  @param  fromLength  length of the input string (number of bytes without
@@ -199,10 +208,10 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                      always regarded as delimiters (see DICOM PS 3.5).
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition convertString(const char *fromString,
-                              const size_t fromLength,
-                              OFString &toString,
-                              const OFString &delimiters = "");
+    virtual OFCondition convertString(const char *fromString,
+                                      const size_t fromLength,
+                                      OFString &toString,
+                                      const OFString &delimiters = "");
 
     // --- static helper functions ---
 
@@ -233,7 +242,7 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                     output string
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition determineDestinationEncoding(const OFString &toCharset);
+    virtual OFCondition determineDestinationEncoding(const OFString &toCharset);
 
     /** select a particular DICOM character set without code extensions for
      *  subsequent conversions.  The corresponding DICOM defined term for the
@@ -241,7 +250,7 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  'SourceCharacterSet'.
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition selectCharacterSetWithoutCodeExtensions();
+    virtual OFCondition selectCharacterSetWithoutCodeExtensions();
 
     /** select a particular DICOM character set with code extensions for
      *  subsequent conversions.  The corresponding DICOM defined terms for the
@@ -252,8 +261,39 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *                    already been determined by the calling method.
      *  @return status, EC_Normal if successful, an error code otherwise
      */
-    OFCondition selectCharacterSetWithCodeExtensions(const unsigned long sourceVM);
+    virtual OFCondition selectCharacterSetWithCodeExtensions(const unsigned long sourceVM);
+
+    /** convert the given string from the selected source character set (without
+     *  code extensions) to the selected destination character set
+     *  @param  fromString  input string to be converted
+     *  @param  fromLength  length of the input string (in bytes)
+     *  @param  toString    reference to variable where to store the converted
+     *                      string
+     *  @param  delimiters  string of characters regarded as delimiters
+     *  @return status, EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition convertStringWithoutCodeExtensions(const char *fromString,
+                                                           const size_t fromLength,
+                                                           OFString &toString,
+                                                           const OFString &delimiters);
 
+    /** convert the given string from the selected source character set(s) to
+     *  the selected destination character set.  This method supports code
+     *  extension techniques according to ISO 2022 for the input string.
+     *  @param  fromString     input string to be converted
+     *  @param  fromLength     length of the input string (in bytes)
+     *  @param  toString       reference to variable where to store the
+     *                         converted string
+     *  @param  delimiters     string of characters regarded as delimiters
+     *  @param  hasEscapeChar  flag indicating wether the input string contains
+     *                         one or more escape characters (ESC)
+     *  @return status, EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition convertStringWithCodeExtensions(const char *fromString,
+                                                        const size_t fromLength,
+                                                        OFString &toString,
+                                                        const OFString &delimiters,
+                                                        const OFBool hasEscapeChar);
 
     /** check whether the given string contains at least one escape character
      *  (ESC), because it is used for code extension techniques like ISO 2022
@@ -261,8 +301,8 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @param  strLength  length of the input string
      *  @return OFTrue if an escape character has been found, OFFalse otherwise
      */
-    OFBool checkForEscapeCharacter(const char *strValue,
-                                   const size_t strLength) const;
+    virtual OFBool checkForEscapeCharacter(const char *strValue,
+                                           const size_t strLength) const;
 
     /** convert given string to octal format, i.e.\ all non-ASCII and control
      *  characters are converted to their octal representation.  The total
@@ -273,8 +313,8 @@ class DCMTK_DCMDATA_EXPORT DcmSpecificCharacterSet
      *  @param  strLength  length of the input string
      *  @return resulting string in octal format
      */
-    OFString convertToLengthLimitedOctalString(const char *strValue,
-                                               const size_t strLength) const;
+    virtual OFString convertToLengthLimitedOctalString(const char *strValue,
+                                                       const size_t strLength) const;
 
 
   private:
index a3952a9aa944025776b757fa7becbba0d5b2a885..dfe056990cc499baacce06f864e12e4f0ef39351 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2021, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmdata/dcdefine.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 /* needed e.g. on Solaris for definition of size_t */
 #include <sys/types.h>
-#endif
 END_EXTERN_C
 
 /*
@@ -157,7 +155,7 @@ typedef enum {
     EWM_dataset = 1,
     /// write as fileformat and update required information (e.g. SOP Class/Instance UID)
     EWM_updateMeta = 2,
-    /// write as fileformat and create new meta header (do not retain existing information)
+    /// write as fileformat and create new meta header (do not retain existing information except SOP Class/Instance UID)
     EWM_createNewMeta = 3,
     /// write as fileformat but don't update the meta header (please be careful!)
     EWM_dontUpdateMeta = 4
@@ -173,7 +171,7 @@ struct DCMTK_DCMDATA_EXPORT DCMTypes
     /** @name print() flags.
      *  These flags can be combined and passed to the print() methods.
      */
-    //@{
+    ///@{
 
     /// shorten long tag values (e.g. long texts, pixel data)
     static const size_t PF_shortenLongTagValues;
@@ -192,12 +190,12 @@ struct DCMTK_DCMDATA_EXPORT DCMTypes
 
     /// use ANSI escape codes for output
     static const size_t PF_useANSIEscapeCodes;
-    //@}
+    ///@}
 
     /** @name writeXML() flags.
      *  These flags can be combined and passed to the writeXML() methods.
      */
-    //@{
+    ///@{
 
     /// add document type definition (DTD). DCMTK-specific format only.
     static const size_t XF_addDocumentType;
@@ -226,12 +224,12 @@ struct DCMTK_DCMDATA_EXPORT DCMTypes
     /// The default is to use the DCMTK-specific format.
     static const size_t XF_useNativeModel;
 
-    //@}
+    ///@}
 
     /** @name convertCharacterSet() flags.
      *  These flags can be combined and passed to the convertCharacterSet() methods.
      */
-    //@{
+    ///@{
 
     /// try to approximate characters that cannot be represented through similar
     /// looking characters.  See DcmSpecificCharacterSet::getTransliterationMode().
@@ -241,7 +239,7 @@ struct DCMTK_DCMDATA_EXPORT DCMTypes
     /// See DcmSpecificCharacterSet::getDiscardIllegalSequenceMode().
     static const size_t CF_discardIllegal;
 
-    //@}
+    ///@}
 };
 
 
index 769e535441d7c5b75feca098a2f294ba3b903c8b..08a7b8e64befe5517bdd5379e17981288c87de26 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -436,6 +436,8 @@ DCMTK_DCMDATA_EXPORT unsigned long dcmGuessModalityBytes(const char *sopClassUID
 #define UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax "1.2.840.10008.1.2.1.98"
 /// Deflated Explicit VR Little Endian
 #define UID_DeflatedExplicitVRLittleEndianTransferSyntax "1.2.840.10008.1.2.1.99"
+/// Deflated Image Frame Compression
+#define UID_DeflatedImageFrameCompressionTransferSyntax  "1.2.840.10008.1.2.8.1"
 /** JPEG Baseline (Process 1): Default Transfer Syntax
  *  for Lossy JPEG 8 Bit Image Compression
  */
@@ -622,6 +624,8 @@ DCMTK_DCMDATA_EXPORT unsigned long dcmGuessModalityBytes(const char *sopClassUID
 #define UID_ElectrooculogramWaveformStorage                        "1.2.840.10008.5.1.4.1.1.9.7.3"
 #define UID_SleepElectroencephalogramWaveformStorage               "1.2.840.10008.5.1.4.1.1.9.7.4"
 #define UID_BodyPositionWaveformStorage                            "1.2.840.10008.5.1.4.1.1.9.8.1"
+#define UID_WaveformPresentationStateStorage                       "1.2.840.10008.5.1.4.1.1.9.100.1"
+#define UID_WaveformAcquisitionPresentationStateStorage            "1.2.840.10008.5.1.4.1.1.9.100.2"
 #define UID_RETIRED_StandaloneModalityLUTStorage                   "1.2.840.10008.5.1.4.1.1.10"
 #define UID_RETIRED_StandaloneVOILUTStorage                        "1.2.840.10008.5.1.4.1.1.11"
 #define UID_GrayscaleSoftcopyPresentationStateStorage              "1.2.840.10008.5.1.4.1.1.11.1"
@@ -777,6 +781,7 @@ DCMTK_DCMDATA_EXPORT unsigned long dcmGuessModalityBytes(const char *sopClassUID
 #define UID_DICONDE_EddyCurrentMultiframeImageStorage              "1.2.840.10008.5.1.4.1.1.601.2"
 #define UID_DICONDE_ThermographyImageStorage                       "1.2.840.10008.5.1.4.1.1.601.3"
 #define UID_DICONDE_ThermographyMultiFrameImageStorage             "1.2.840.10008.5.1.4.1.1.601.4"
+#define UID_DICONDE_UltrasoundWaveformStorage                      "1.2.840.10008.5.1.4.1.1.601.5"
 
 // Query/Retrieve
 #define UID_FINDPatientRootQueryRetrieveInformationModel           "1.2.840.10008.5.1.4.1.2.1.1"
index df66f187fbcb0978844d24b6bb476e7a589f1c13..1c0c66466304ababde64eac8cc02ed21fdfa54e5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -102,8 +102,8 @@ class DCMTK_DCMDATA_EXPORT DcmApplicationEntity
      *  @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition getOFString(OFString &stringVal,
-                                       const unsigned long pos,
-                                       OFBool normalize = OFTrue);
+                                    const unsigned long pos,
+                                    OFBool normalize = OFTrue);
 
     // ensure inherited overloads of matches take part in overload resolution
     using DcmByteString::matches;
index fa0457c77566578afd7e74c1c2d9bb268efd93a1..ed11020f670ed9cbc330eb7794910bcd3cc3bba1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2021, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -369,6 +369,22 @@ class DCMTK_DCMDATA_EXPORT DcmOtherByteOtherWord
                     const char *pixelFileName,
                     size_t *pixelCounter);
 
+    /**
+     * compares two binary values for equality.
+     * This function compares the binary data pointed to by `myValue` and `rhsValue`
+     * for equality up to the specified length `valLength`. See compare() method
+     * for more details.
+     *
+     * @param myValue pointer to the first value to compare.
+     * @param rhsValue pointer to the second value to compare.
+     * @param valLength the number of bytes to compare.
+     * @return an integer less than, equal to, or greater than zero if the first value
+     *         is found to be less than, equal to, or greater than the second value.
+     */
+    virtual int compareValues(const void* myValue,
+                              const void* rhsValue,
+                              const unsigned long valLength) const;
+
 private:
 
     /** this flag is used during write operations and indicates that compact() should be
index 93a7d6880cd647bc8816c1047eb5fb0be8d1cfbc..16af105aa39785d7a550c1929583a6e9312de35a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -88,72 +88,74 @@ typedef enum {
     EXS_RLELossless = 23,
     /// Deflated Explicit VR Little Endian
     EXS_DeflatedLittleEndianExplicit = 24,
+    /// Deflated Image Frame Compression
+    EXS_DeflatedImageFrameCompression = 25,
     /// JPEG-LS (lossless)
-    EXS_JPEGLSLossless = 25,
+    EXS_JPEGLSLossless = 26,
     /// JPEG-LS (lossless or near-lossless mode)
-    EXS_JPEGLSLossy = 26,
+    EXS_JPEGLSLossy = 27,
     /// JPEG 2000 (lossless)
-    EXS_JPEG2000LosslessOnly = 27,
+    EXS_JPEG2000LosslessOnly = 28,
     /// JPEG 2000 (lossless or lossy)
-    EXS_JPEG2000 = 28,
+    EXS_JPEG2000 = 29,
     /// JPEG 2000 part 2 multi-component extensions (lossless)
-    EXS_JPEG2000MulticomponentLosslessOnly = 29,
+    EXS_JPEG2000MulticomponentLosslessOnly = 30,
     /// JPEG 2000 part 2 multi-component extensions (lossless or lossy)
-    EXS_JPEG2000Multicomponent = 30,
+    EXS_JPEG2000Multicomponent = 31,
     /// JPIP Referenced
-    EXS_JPIPReferenced = 31,
+    EXS_JPIPReferenced = 32,
     /// JPIP Referenced Deflate
-    EXS_JPIPReferencedDeflate = 32,
+    EXS_JPIPReferencedDeflate = 33,
     /// MPEG2 Main Profile at Main Level
-    EXS_MPEG2MainProfileAtMainLevel = 33,
+    EXS_MPEG2MainProfileAtMainLevel = 34,
     /// Fragmentable MPEG2 Main Profile / Main Level
-    EXS_FragmentableMPEG2MainProfileMainLevel = 34,
+    EXS_FragmentableMPEG2MainProfileMainLevel = 35,
     /// MPEG2 Main Profile at High Level
-    EXS_MPEG2MainProfileAtHighLevel = 35,
+    EXS_MPEG2MainProfileAtHighLevel = 36,
     /// Fragmentable MPEG2 Main Profile / High Level
-    EXS_FragmentableMPEG2MainProfileHighLevel = 36,
+    EXS_FragmentableMPEG2MainProfileHighLevel = 37,
     /// MPEG4 High Profile / Level 4.1
-    EXS_MPEG4HighProfileLevel4_1 = 37,
+    EXS_MPEG4HighProfileLevel4_1 = 38,
     /// Fragmentable MPEG4 High Profile / Level 4.1
-    EXS_FragmentableMPEG4HighProfileLevel4_1 = 38,
+    EXS_FragmentableMPEG4HighProfileLevel4_1 = 39,
     /// MPEG4 BD-compatible High Profile / Level 4.1
-    EXS_MPEG4BDcompatibleHighProfileLevel4_1 = 39,
+    EXS_MPEG4BDcompatibleHighProfileLevel4_1 = 40,
     /// Fragmentable MPEG4 BD-compatible High Profile / Level 4.1
-    EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1 = 40,
+    EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1 = 41,
     /// MPEG4 High Profile / Level 4.2 For 2D Video
-    EXS_MPEG4HighProfileLevel4_2_For2DVideo = 41,
+    EXS_MPEG4HighProfileLevel4_2_For2DVideo = 42,
     /// Fragmentable MPEG4 High Profile / Level 4.2 For 2D Video
-    EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo = 42,
+    EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo = 43,
     /// MPEG4 High Profile / Level 4.2 For 3D Video
-    EXS_MPEG4HighProfileLevel4_2_For3DVideo = 43,
+    EXS_MPEG4HighProfileLevel4_2_For3DVideo = 44,
     /// Fragmentable MPEG4 Stereo High Profile / Level 4.2
-    EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo = 44,
+    EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo = 45,
     /// MPEG4 Stereo High Profile / Level 4.2
-    EXS_MPEG4StereoHighProfileLevel4_2 = 45,
+    EXS_MPEG4StereoHighProfileLevel4_2 = 46,
     /// Fragmentable HEVC/H.265 Main Profile / Level 5.1
-    EXS_FragmentableMPEG4StereoHighProfileLevel4_2 = 46,
+    EXS_FragmentableMPEG4StereoHighProfileLevel4_2 = 47,
     /// HEVC/H.265 Main Profile / Level 5.1
-    EXS_HEVCMainProfileLevel5_1 = 47,
+    EXS_HEVCMainProfileLevel5_1 = 48,
     /// HEVC/H.265 Main 10 Profile / Level 5.1
-    EXS_HEVCMain10ProfileLevel5_1 = 48,
+    EXS_HEVCMain10ProfileLevel5_1 = 49,
     /// JPEG XL Lossless
-    EXS_JPEGXLLossless = 49,
+    EXS_JPEGXLLossless = 50,
     /// JPEG XL JPEG Recompression
-    EXS_JPEGXLJPEGRecompression = 50,
+    EXS_JPEGXLJPEGRecompression = 51,
     /// JPEG XL
-    EXS_JPEGXL = 51,
+    EXS_JPEGXL = 52,
     /// High-Throughput JPEG 2000 Image Compression (Lossless Only)
-    EXS_HighThroughputJPEG2000LosslessOnly = 52,
+    EXS_HighThroughputJPEG2000LosslessOnly = 53,
     /// High-Throughput JPEG 2000 with RPCL Options Image Compression (Lossless Only)
-    EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly = 53,
+    EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly = 54,
     /// High-Throughput JPEG 2000 Image Compression
-    EXS_HighThroughputJPEG2000 = 54,
+    EXS_HighThroughputJPEG2000 = 55,
     /// JPIP HTJ2K Referenced
-    EXS_JPIPHTJ2KReferenced = 55,
+    EXS_JPIPHTJ2KReferenced = 56,
     /// JPIP HTJ2K Referenced Deflate
-    EXS_JPIPHTJ2KReferencedDeflate = 56,
+    EXS_JPIPHTJ2KReferencedDeflate = 57,
     /// Private GE Little Endian Implicit with big endian pixel data
-    EXS_PrivateGE_LEI_WithBigEndianPixelData = 57
+    EXS_PrivateGE_LEI_WithBigEndianPixelData = 58
 } E_TransferSyntax;
 
 
@@ -555,6 +557,23 @@ public:
         return isPixelDataLosslessCompressed() || isDatasetCompressed();
     }
 
+    /** get DICOMweb MIME type for pixel data in this transfer syntax
+     *  @return DICOMweb MIME type for pixel data in this transfer syntax
+     */
+    inline const char *getMIMEType() const
+    {
+        return mimeType;
+    }
+
+    /** get suggested filename extension to use when storing pixel data
+     *  of this transfer syntax as bulk data for use with DICOMweb
+     *  @return suggested filename extension
+     */
+    inline const char *getFilenameExtension() const
+    {
+        return filenameExtension;
+    }
+
     /** get the number of bytes needed to describe the tag, length, VR and any
      *  reserved fields for this transfer syntax when encoding the specified VR.
      *  @param evr value representation to be encoded in this transfer syntax
@@ -601,6 +620,13 @@ private:
 
     /// validity of the transfer syntax definition (e.g. standard, retired, private)
     E_XferValidity         xferValidity;
+
+    /// MIME type used for this transfer syntax in DICOMweb
+    const char            *mimeType;
+
+    /// file name extension for storing bulk data in this transfer syntax
+    const char            *filenameExtension;
+
 };
 
 /** global constant describing the byte order on the machine the application
index e612dc75d359e09df78e7a17f1ade35f3304c556..b8b4a566980c23a849ff7e65f1bef5ac96715fb8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -45,7 +45,7 @@ public:
 
   /** Destructor, frees plugin memory
    */
-  ~Image2Dcm();
+  virtual ~Image2Dcm();
 
   /** Start the conversion. Needs a fully configured input plugin
    *  and a fully configured output plugin to operate. Returns
@@ -79,6 +79,12 @@ public:
     I2DImgSource *inputPlug,
     size_t frameNumber);
 
+  /** Adjust byte order of the pixel data to local byte order for the OW VR.
+   *  @param numberOfFrames - [in] The number of frames to be written
+   *  @return EC_Normal, if successful, error otherwise
+   */
+  virtual OFCondition adjustByteOrder(size_t numberOfFrames);
+
   /** Update the offset table in the case of an encapsulated image
    *  @return EC_Normal if offset table could be updated, error code otherwise
    */
@@ -197,6 +203,7 @@ protected:
   /** Reads pixel data and corresponding attributes like rows etc. from image
    *  file and inserts them into dataset.
    *  @param imageSource - [in] The input plugin that actually reads the pixel data
+   *  @param outPlug - [in] The output plugin for specific SOP class output
    *  @param numberOfFrames - [in] The number of frames to be written
    *  @param dset - [out] The dataset to export the pixel data attributes to
    *  @param outputTS - [out] The proposed transfex syntax of the dataset
@@ -205,6 +212,7 @@ protected:
    */
   OFCondition readAndInsertPixelDataFirstFrame(
     I2DImgSource* imageSource,
+    I2DOutputPlug *outPlug,
     size_t numberOfFrames,
     DcmDataset* dset,
     E_TransferSyntax& outputTS,
index 8d15f2bcd607f0d46690164734d48bfb6f38aec9..d9ce86dbf656a069f874f7ad0464ef7db82b529d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2022, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -259,13 +259,15 @@ protected:
      *  @param imageHeight - [out] The height of the image
      *  @param samplesPerPixel - [out] Number of components per pixel
      *  @param bitsPerSample - [out] Number of bits per pixel component
+     *  @param colorModel - [out] color model of the JPEG bitstream
      *  @return EC_Normal, if successful, error otherwise
      */
     OFCondition getSOFImageParameters(const JPEGFileMapEntry& entry,
                                       Uint16& imageWidth,
                                       Uint16& imageHeight,
                                       Uint16& samplesPerPixel,
-                                      Uint16& bitsPerSample);
+                                      Uint16& bitsPerSample,
+                                      OFString& colorModel);
 
     /** Get image parameters as found at given SOF marker of the JPEG image.
      *  Used for JPEG-LS codec.
index 5fe902792e3688e90416c704da2fd054d5d04c72..9e74e0b9b60b2e3260618276420cbb133753074a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,6 +26,7 @@
 #include "dcmtk/oflog/oflog.h"
 #include "dcmtk/ofstd/oflist.h"
 #include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmdata/dcxfer.h"
 #include "dcmtk/dcmdata/libi2d/i2define.h"
 
 extern DCMTK_I2D_EXPORT OFLogger DCM_dcmdataLibi2dLogger;
@@ -86,6 +87,21 @@ public:
    */
   virtual OFBool supportsMultiframe() const = 0;
 
+  /** checks if the output SOP class permits the given combination of
+   *  transfer syntax and photometric interpretation
+   *  @param photometricInterpretation  - [in] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return true if combination permitted, false otherwise
+   */
+  virtual OFBool colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const = 0;
+
+  /** change the photometric interpretation to the next best permitted one, for lenient mode
+   *  @param photometricInterpretation  - [in/out] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return EC_Normal if a "compatible" replacement exists, an error code otherwise
+   */
+  virtual OFCondition updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const = 0;
+
   /** Add multiframe specific attributes
    *  @param targetDataset pointer to DICOM dataset, must not be NULL
    *  @param numberOfFrames number of frames in this dataset
index 36b321e5edb1e5541a441555234b7413b54c2c38..e65c663912d7258b96e7a5f1adc08ea7f9ece34c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -71,6 +71,21 @@ public:
    */
   virtual OFBool supportsMultiframe() const;
 
+  /** checks if the output SOP class permits the given combination of
+   *  transfer syntax and photometric interpretation
+   *  @param photometricInterpretation  - [in] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return true if combination permitted, false otherwise
+   */
+  virtual OFBool colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
+  /** change the photometric interpretation to the next best permitted one, for lenient mode
+   *  @param photometricInterpretation  - [in/out] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return EC_Normal if a "compatible" replacement exists, an error code otherwise
+   */
+  virtual OFCondition updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
   /** Add multiframe specific attributes
    *  @param targetDataset pointer to DICOM dataset, must not be NULL
    *  @param numberOfFrames number of frames in this dataset
index 8980297914b65b0f470f2426e12d40a084158df8..d0f495cfc62493b5372f8d1627c645028c4ac34b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -70,6 +70,21 @@ public:
    */
   virtual OFBool supportsMultiframe() const;
 
+  /** checks if the output SOP class permits the given combination of
+   *  transfer syntax and photometric interpretation
+   *  @param photometricInterpretation  - [in] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return true if combination permitted, false otherwise
+   */
+  virtual OFBool colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
+  /** change the photometric interpretation to the next best permitted one, for lenient mode
+   *  @param photometricInterpretation  - [in/out] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return EC_Normal if a "compatible" replacement exists, an error code otherwise
+   */
+  virtual OFCondition updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
   /** Add multiframe specific attributes
    *  @param targetDataset pointer to DICOM dataset, must not be NULL
    *  @param numberOfFrames number of frames in this dataset
index 0a4edf58bbe5f02697c835bee61a97e9665292d5..1f51a819675b5d8d04338c2ee5668c3f0cfaf040 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -70,6 +70,21 @@ public:
    */
   virtual OFBool supportsMultiframe() const;
 
+  /** checks if the output SOP class permits the given combination of
+   *  transfer syntax and photometric interpretation
+   *  @param photometricInterpretation  - [in] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return true if combination permitted, false otherwise
+   */
+  virtual OFBool colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
+  /** change the photometric interpretation to the next best permitted one, for lenient mode
+   *  @param photometricInterpretation  - [in/out] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return EC_Normal if a "compatible" replacement exists, an error code otherwise
+   */
+  virtual OFCondition updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
   /** Add multiframe specific attributes
    *  @param targetDataset pointer to DICOM dataset, must not be NULL
    *  @param numberOfFrames number of frames in this dataset
index 4bbf34983eef6668a76c4b5c877e03f1e49e3bc5..e4a323aa919c88f92c71659e787d73cf98e32aa9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -70,6 +70,21 @@ public:
    */
   virtual OFBool supportsMultiframe() const;
 
+  /** checks if the output SOP class permits the given combination of
+   *  transfer syntax and photometric interpretation
+   *  @param photometricInterpretation  - [in] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return true if combination permitted, false otherwise
+   */
+  virtual OFBool colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
+  /** change the photometric interpretation to the next best permitted one, for lenient mode
+   *  @param photometricInterpretation  - [in/out] photometric interpretation
+   *  @param outputTS - [in] output transfer syntax
+   *  @return EC_Normal if a "compatible" replacement exists, an error code otherwise
+   */
+  virtual OFCondition updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const;
+
   /** Add multiframe specific attributes
    *  @param targetDataset pointer to DICOM dataset, must not be NULL
    *  @param numberOfFrames number of frames in this dataset
index bcf6e4ff99f4eba83f51b7486dd63c2c28e24870..525bd32807568026c143ae88e7ffe5f6d4e18d61 100644 (file)
@@ -3,61 +3,4 @@ xml2dcm.o: xml2dcm.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcmxml/dcxmldf.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
- ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
- ../../oflog/include/dcmtk/oflog/oflog.h \
- ../../oflog/include/dcmtk/oflog/logger.h \
- ../../oflog/include/dcmtk/oflog/config.h \
- ../../oflog/include/dcmtk/oflog/config/defines.h \
- ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
- ../../oflog/include/dcmtk/oflog/loglevel.h \
- ../../ofstd/include/dcmtk/ofstd/ofvector.h \
- ../../oflog/include/dcmtk/oflog/tstring.h \
- ../../oflog/include/dcmtk/oflog/tchar.h \
- ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
- ../../oflog/include/dcmtk/oflog/appender.h \
- ../../ofstd/include/dcmtk/ofstd/ofmem.h \
- ../../ofstd/include/dcmtk/ofstd/ofutil.h \
- ../../ofstd/include/dcmtk/ofstd/oftraits.h \
- ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
- ../../oflog/include/dcmtk/oflog/layout.h \
- ../../oflog/include/dcmtk/oflog/streams.h \
- ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
- ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
- ../../oflog/include/dcmtk/oflog/spi/filter.h \
- ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
- ../../oflog/include/dcmtk/oflog/spi/logfact.h \
- ../../oflog/include/dcmtk/oflog/logmacro.h \
- ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
- ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../include/dcmtk/dcmdata/dcsequen.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dcelem.h ../include/dcmtk/dcmdata/dcobject.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dctag.h \
- ../include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dcpcache.h \
- ../include/dcmtk/dcmdata/dcpixseq.h ../include/dcmtk/dcmdata/dcofsetl.h \
- ../include/dcmtk/dcmdata/dcpixel.h ../include/dcmtk/dcmdata/dcvrpobw.h \
- ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcpxitem.h \
- ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcfilefo.h \
- ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcmetinf.h \
- ../include/dcmtk/dcmdata/dcswap.h
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h
index 6c134a3bbeb8cd9e15e67a05f68c16850d1ea18c..ae268f2f10f7a7e120e42ac4653d0785fdd12e34 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2003-2024, OFFIS e.V.
+ *  Copyright (C) 2003-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmdata/dcfilefo.h"
 #include "dcmtk/dcmdata/dcmetinf.h"
 #include "dcmtk/dcmdata/dcswap.h"
+#include "dcmtk/ofstd/ofdiag.h"
+
+// MacOS 15.5 defines some Clang specific pragmas in libxml header files.
+// Suppress warnings caused by these pragmas when compiling with GCC.
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC
 #include <libxml/parser.h>
+#include DCMTK_DIAGNOSTIC_POP
 
 // This function is also used in dcmsr, try to stay in sync!
-#if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
 extern "C" void xml2dcm_errorFunction(void * ctx, const char *msg, ...)
 {
     // Classic C requires us to declare variables at the beginning of the function.
     OFString &buffer = *OFstatic_cast(OFString*, ctx);
-#else
-extern "C" void xml2dcm_errorFunction(void * /* ctx */, const char *msg, ...)
-{
-#endif
 
     if (!DCM_dcmdataLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
         return;
 
-#if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
     // libxml calls us multiple times for one line of log output which would
     // result in garbled output. To avoid this, we buffer the output in a local
     // string in the caller which we get through our 'ctx' parameter. Then, we
@@ -82,17 +83,6 @@ extern "C" void xml2dcm_errorFunction(void * /* ctx */, const char *msg, ...)
 
         pos = buffer.find('\n');
     }
-#else
-    // No vsnprint, but at least vfprintf. Output the messages directly to stderr.
-    va_list ap;
-    va_start(ap, msg);
-#ifdef HAVE_PROTOTYPE_STD__VFPRINTF
-    std::vfprintf(stderr, msg, ap);
-#else
-    vfprintf(stderr, msg, ap);
-#endif
-    va_end(ap);
-#endif
 }
 
 
index 6a1fa7f0adb8bb3f2b5bd1916df0a4d8f3712a26..c6dbd94829f0f77047d3db7b5726d9160fa05291 100644 (file)
@@ -39,13 +39,13 @@ i2d.o: i2d.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmdata/libi2d/i2define.h \
- ../include/dcmtk/dcmdata/libi2d/i2dimgs.h \
  ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
  ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/libi2d/i2define.h \
+ ../include/dcmtk/dcmdata/libi2d/i2dimgs.h \
  ../include/dcmtk/dcmdata/dcpixel.h ../include/dcmtk/dcmdata/dcvrpobw.h \
  ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
@@ -62,6 +62,7 @@ i2d.o: i2d.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcuid.h \
  ../include/dcmtk/dcmdata/dcpixseq.h ../include/dcmtk/dcmdata/dcpath.h \
+ ../include/dcmtk/dcmdata/dcswap.h \
  ../include/dcmtk/dcmdata/dcmxml/xml2dcm.h \
  ../include/dcmtk/dcmdata/dcmxml/dcxmldf.h
 i2dbmps.o: i2dbmps.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -210,19 +211,18 @@ i2doutpl.o: i2doutpl.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../include/dcmtk/dcmdata/libi2d/i2define.h \
  ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcdefine.h \
- ../include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
- ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
  ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
@@ -269,9 +269,13 @@ i2dplnsc.o: i2dplnsc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../include/dcmtk/dcmdata/libi2d/i2define.h \
  ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dctagkey.h \
- ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmdata/dcitem.h \
@@ -279,12 +283,7 @@ i2dplnsc.o: i2dplnsc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
- ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
  ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcstack.h \
  ../include/dcmtk/dcmdata/dclist.h ../include/dcmtk/dcmdata/dcpcache.h
 i2dplop.o: i2dplop.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -328,9 +327,13 @@ i2dplop.o: i2dplop.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../include/dcmtk/dcmdata/libi2d/i2define.h \
  ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dctagkey.h \
- ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmdata/dcuid.h \
  ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
@@ -341,12 +344,7 @@ i2dplop.o: i2dplop.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
- ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
  ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcstack.h \
  ../include/dcmtk/dcmdata/dclist.h ../include/dcmtk/dcmdata/dcpcache.h
 i2dplsc.o: i2dplsc.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -390,9 +388,13 @@ i2dplsc.o: i2dplsc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../include/dcmtk/dcmdata/libi2d/i2define.h \
  ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dctagkey.h \
- ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmdata/dcitem.h \
@@ -400,12 +402,7 @@ i2dplsc.o: i2dplsc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
- ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
  ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcstack.h \
  ../include/dcmtk/dcmdata/dclist.h ../include/dcmtk/dcmdata/dcpcache.h
 i2dplvlp.o: i2dplvlp.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -449,9 +446,13 @@ i2dplvlp.o: i2dplvlp.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmdata/dcxfer.h ../include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../include/dcmtk/dcmdata/libi2d/i2define.h \
  ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dctagkey.h \
- ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmdata/dcitem.h \
@@ -459,11 +460,6 @@ i2dplvlp.o: i2dplvlp.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
- ../include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dcerror.h \
  ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dcstack.h \
  ../include/dcmtk/dcmdata/dclist.h ../include/dcmtk/dcmdata/dcpcache.h
index 73897652fd62422640c75b0d0d382ff2639f63eb..c24189bca0e31f2512b73f31981985dd0520bea4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2024, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmdata/libi2d/i2d.h"
 #include "dcmtk/ofstd/ofstd.h"
 #include "dcmtk/dcmdata/dcpxitem.h"
-#include "dcmtk/dcmdata/dcfilefo.h"  /* for DcmFileFormat */
-#include "dcmtk/dcmdata/dcdeftag.h"  /* for DCM_ defines */
-#include "dcmtk/dcmdata/dcuid.h"     /* for SITE_SERIES_UID_ROOT */
-#include "dcmtk/dcmdata/dcpixseq.h"  /* for DcmPixelSequence */
-#include "dcmtk/dcmdata/dcpath.h"    /* for override keys */
-#include "dcmtk/dcmdata/dcmxml/xml2dcm.h"   /* for DcmXMLParseHelper */
+#include "dcmtk/dcmdata/dcfilefo.h"        /* for DcmFileFormat */
+#include "dcmtk/dcmdata/dcdeftag.h"        /* for DCM_ defines */
+#include "dcmtk/dcmdata/dcuid.h"           /* for SITE_SERIES_UID_ROOT */
+#include "dcmtk/dcmdata/dcpixseq.h"        /* for DcmPixelSequence */
+#include "dcmtk/dcmdata/dcpath.h"          /* for override keys */
+#include "dcmtk/dcmdata/dcswap.h"          /* for swapIfNecessary() */
+#include "dcmtk/dcmdata/dcmxml/xml2dcm.h"  /* for DcmXMLParseHelper */
 
 OFLogger DCM_dcmdataLibi2dLogger = OFLog::getLogger("dcmtk.dcmdata.libi2d");
 
@@ -147,7 +148,7 @@ OFCondition Image2Dcm::convertFirstFrame(
 
   // Read and insert pixel data
   m_compressionRatio = 1.0;
-  cond = readAndInsertPixelDataFirstFrame(inputPlug, numberOfFrames, tempDataset.get(), proposedTS, m_compressionRatio);
+  cond = readAndInsertPixelDataFirstFrame(inputPlug, outPlug, numberOfFrames, tempDataset.get(), proposedTS, m_compressionRatio);
   if (cond.bad())
   {
     return cond;
@@ -584,6 +585,7 @@ OFCondition Image2Dcm::insertEncapsulatedPixelDataNextFrame(
 
 OFCondition Image2Dcm::readAndInsertPixelDataFirstFrame(
   I2DImgSource* imgSource,
+  I2DOutputPlug *outPlug,
   size_t numberOfFrames,
   DcmDataset* dset,
   E_TransferSyntax& outputTS,
@@ -652,6 +654,22 @@ OFCondition Image2Dcm::readAndInsertPixelDataFirstFrame(
   if (cond.bad())
     return cond;
 
+  if (! outPlug->colorModelPermitted(m_photometricInterpretation, outputTS))
+  {
+      OFString old_photometricInterpretation = m_photometricInterpretation;
+      cond = outPlug->updateColorModel(m_photometricInterpretation, outputTS);
+      DcmXfer xf(outputTS);
+      if (cond.good())
+      {
+          DCMDATA_LIBI2D_WARN("Image2Dcm: photometric interpretation '" << old_photometricInterpretation << "' not permitted for the selected SOP class in '" << xf.getXferName() << "' transfer syntax, using '" << m_photometricInterpretation << "' instead");
+      }
+      else
+      {
+          DCMDATA_LIBI2D_ERROR("Image2Dcm: photometric interpretation '" << old_photometricInterpretation << "' not permitted for the selected SOP class in '" << xf.getXferName() << "' transfer syntax");
+          return cond;
+      }
+  }
+
   cond = dset->putAndInsertOFStringArray(DCM_PhotometricInterpretation, m_photometricInterpretation);
   if (cond.bad())
     return cond;
@@ -1040,3 +1058,22 @@ OFCondition Image2Dcm::updateOffsetTable()
   if (m_offsetTable) result = m_offsetTable->createOffsetTable(m_offsetList);
   return result;
 }
+
+
+OFCondition Image2Dcm::adjustByteOrder(size_t numberOfFrames)
+{
+  if (m_output_buffer)
+  {
+    // unencapsulated pixel data, byte swapping may be necessary
+    if (m_bitsAllocated < 9)
+    {
+      size_t bufSize = m_frameLength * numberOfFrames;
+      if (bufSize & 1) ++bufSize;
+      if (bufSize > 1)
+      {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, m_output_buffer, OFstatic_cast(Uint32, bufSize), sizeof(Uint16));
+      }
+    }
+  }
+  return EC_Normal;
+}
index e9e9c5c7af7a6937381466e4360abe4e4a5ee79e..001e8cd607e9367251dbffc35637cd769c418a93 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2024, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -199,7 +199,7 @@ OFCondition I2DJpegSource::readPixelData(Uint16& rows,
 
     // Extract width, height, samples per pixel, bits per sample
     Uint16 width, height, spp, bps;
-    cond = getSOFImageParameters(**entry, width, height, spp, bps);
+    cond = getSOFImageParameters(**entry, width, height, spp, bps, photoMetrInt);
     if (cond.bad())
     {
         closeFile();
@@ -258,36 +258,27 @@ OFCondition I2DJpegSource::readPixelData(Uint16& rows,
     cols            = width;
     samplesPerPixel = spp;
     bitsStored      = bps;
-    bitsAlloc       = bps;
 
-    // When BitsStored = 12, we use BitsAllocated = 16
-    if (bitsAlloc == 12)
-    {
-        bitsAlloc = 16;
-    }
+    // bitsAlloc is always the next largest multiple of 8
+    if (bitsStored <= 8)
+        bitsAlloc = 8;
+        else bitsAlloc = 16;
 
     // HighBit is always BitsStored - 1.
-    highBit = bitsStored;
-    highBit--;
+    highBit = bitsStored -1;
 
-    if (samplesPerPixel == 1)
-        photoMetrInt = "MONOCHROME2";
-    else if (samplesPerPixel == 3)
+    if ((samplesPerPixel != 1) && (samplesPerPixel != 3))
     {
-        if (m_isJPEGLS)
-          photoMetrInt = "RGB";
-        else
-          photoMetrInt = "YBR_FULL_422";
-    }
-    else
         return makeOFCondition(OFM_dcmdata, 18, OF_error, "For JPEG data, Samples per Pixel must be 1 or 3");
+    }
+
     // Planar Configuration and Pixel Representation is always 0 for JPEG data
     planConf  = 0;
     pixelRepr = 0;
 
     Uint32 tLength   = 0;
     char* tPixelData = NULL;
-    cond             = extractRawJPEGStream(tPixelData, tLength);
+    cond = extractRawJPEGStream(tPixelData, tLength);
     if (cond.bad())
     {
         closeFile();
@@ -320,7 +311,8 @@ OFCondition I2DJpegSource::getSOFImageParameters(const JPEGFileMapEntry& entry,
                                                  Uint16& imageWidth,
                                                  Uint16& imageHeight,
                                                  Uint16& samplesPerPixel,
-                                                 Uint16& bitsPerSample)
+                                                 Uint16& bitsPerSample,
+                                                 OFString& colorModel)
 {
     DCMDATA_LIBI2D_DEBUG("I2DJpegSource: Examining JPEG SOF image parameters");
     if (!isSOFMarker(entry.marker, m_isJPEGLS))
@@ -369,9 +361,79 @@ OFCondition I2DJpegSource::getSOFImageParameters(const JPEGFileMapEntry& entry,
     if (length != OFstatic_cast(unsigned int, 8 + num_components * 3))
         return makeOFCondition(OFM_dcmdata, 18, OF_error, "Bogus SOF marker length");
 
+    if (samplesPerPixel == 1)
+    {
+      colorModel = "MONOCHROME2";
+    }
+    else if (samplesPerPixel == 3)
+    {
+        if (m_isJPEGLS)
+        {
+            colorModel = "RGB";
+        }
+        else
+        {
+            // This is a lossy color JPEG file.
+            // Read component IDs and sampling factors
+            Uint8 i1=0, i2=0, i3=0, ss1=0, ss2=0, ss3=0, n=0;
+            result = read1Byte(i1);
+            if (result != EOF) result = read1Byte(ss1);
+            if (result != EOF) result = read1Byte(n);
+            if (result != EOF) result = read1Byte(i2);
+            if (result != EOF) result = read1Byte(ss2);
+            if (result != EOF) result = read1Byte(n);
+            if (result != EOF) result = read1Byte(i3);
+            if (result != EOF) result = read1Byte(ss3);
+            if (result == EOF)
+                return makeOFCondition(OFM_dcmdata, 18, OF_error, "Premature EOF in JPEG file");
+            if (ss1 == 0x11 && ss2 == 0x11 && ss3 == 0x11)
+            {
+                DCMDATA_LIBI2D_DEBUG("I2DJpegSource:   No subsampling");
+                if (i1 == 'R' && i2 == 'G' && i3 == 'B')
+                {
+                    // an Adobe RGB JPEG
+                    colorModel = "RGB";
+                }
+                else
+                {
+                    // DICOM CP 1654 requires "YBR_FULL_422" to be used for lossy JPEG
+                    // independent from the actual subsampling in use. Therefore, we use
+                    // "YBR_FULL_422" and not "YBR_FULL". See DICOM Part 5, Table 8.2.1-1.
+                    colorModel = "YBR_FULL_422";
+                }
+            }
+            else if (ss1 == 0x21 && ss2 == 0x11 && ss3 == 0x11)
+            {
+                DCMDATA_LIBI2D_DEBUG("I2DJpegSource:   4:2:2 subsampling");
+                colorModel = "YBR_FULL_422";
+            }
+            else if (ss1 == 0x22 && ss2 == 0x11 && ss3 == 0x11)
+            {
+                DCMDATA_LIBI2D_DEBUG("I2DJpegSource:   non-standard 4:2:0 subsampling");
+                DCMDATA_LIBI2D_WARN("JPEG file contains non-standard 4:2:0 subsampling");
+                colorModel = "YBR_FULL_422";
+            }
+            else if (ss1 == 0x41 && ss2 == 0x11 && ss3 == 0x11)
+            {
+                DCMDATA_LIBI2D_DEBUG("I2DJpegSource:   non-standard 4:1:1 subsampling");
+                DCMDATA_LIBI2D_WARN("JPEG file contains non-standard 4:1:1 subsampling");
+                colorModel = "YBR_FULL_422";
+            }
+            else
+            {
+                DCMDATA_LIBI2D_DEBUG("I2DJpegSource:   non-standard subsampling: "
+                    << OFstatic_cast(unsigned int, ss1 >> 4) << "/" << OFstatic_cast(unsigned int, ss1 & 15) << ", "
+                    << OFstatic_cast(unsigned int, ss2 >> 4) << "/" << OFstatic_cast(unsigned int, ss2 & 15) << ", "
+                    << OFstatic_cast(unsigned int, ss3 >> 4) << "/" << OFstatic_cast(unsigned int, ss3 & 15));
+                DCMDATA_LIBI2D_WARN("JPEG file contains non-standard subsampling");
+                colorModel = "YBR_FULL_422";
+            }
+        }
+    }
     return EC_Normal;
 }
 
+
 OFCondition I2DJpegSource::getSOSImageParameters(const JPEGFileMapEntry& entry,
                                                  Uint8& nearLossless)
 {
index 183048e8880112e3d9b08c6fbb201847036edec9..76e9e942baa85e74f1e8202c951d8078fb9d8de6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -259,6 +259,151 @@ OFBool I2DOutputPlugNewSC::supportsMultiframe() const
 }
 
 
+OFBool I2DOutputPlugNewSC::colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return OFTrue;
+
+    // DICOM part 3, section A.8.5.4:
+    // Photometric Interpretation (0028,0004) shall be RGB for uncompressed or lossless compressed Transfer Syntaxes that do not have defined color space transformations,
+    // YBR_ICT for irreversible JPEG 2000 Transfer Syntaxes,
+    // YBR_RCT for reversible JPEG 2000 Transfer Syntaxes,
+    // YBR_PARTIAL_420 for MPEG2, MPEG-4 AVC/H.264, HEVC/H.265 Transfer Syntaxes and
+    // YBR_FULL_422 for JPEG lossy compressed Transfer Syntaxes and
+    // YBR_FULL or RGB for RLE Transfer Syntaxes
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            return (photometricInterpretation == "YBR_ICT");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            return (photometricInterpretation == "YBR_RCT");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            return (photometricInterpretation == "YBR_PARTIAL_420");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            return (photometricInterpretation == "YBR_FULL_422");
+            /* break; */
+        case EXS_RLELossless:
+            return ((photometricInterpretation == "YBR_FULL") || (photometricInterpretation == "RGB"));
+            /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return OFTrue;
+            /* break; */
+        default:
+            return (photometricInterpretation == "RGB");
+            /* break; */
+    }
+}
+
+
+OFCondition I2DOutputPlugNewSC::updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return EC_Normal;
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            if (photometricInterpretation == "YBR_ICT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            if (photometricInterpretation == "YBR_RCT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            if (photometricInterpretation == "YBR_PARTIAL_420") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            // silently replace "YBR_FULL" by "YBR_FULL_422". Most JPEG codecs won't mind.
+            if (photometricInterpretation == "YBR_FULL")
+            {
+                photometricInterpretation = "YBR_FULL_422";
+                return EC_Normal;
+            }
+            else if (photometricInterpretation == "YBR_FULL_422") return EC_Normal;
+            else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_RLELossless:
+            if ((photometricInterpretation == "YBR_FULL") || (photometricInterpretation == "RGB")) return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+           /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return EC_Normal;
+            /* break; */
+        default:
+            if (photometricInterpretation == "RGB") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+    }
+}
+
+
 OFCondition I2DOutputPlugNewSC::insertMultiFrameAttributes(
   DcmDataset* targetDataset,
   size_t numberOfFrames) const
index 3ba7bf53fe4ff3c686672e47031bcf5ee0053b02..51931cd1cc909db0aab0f24d956957edb6a0062f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -278,6 +278,146 @@ OFBool I2DOutputPlugOphthalmicPhotography::supportsMultiframe() const
 }
 
 
+OFBool I2DOutputPlugOphthalmicPhotography::colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return OFTrue;
+
+    // DICOM part 3, C.8.17.2.1.3:
+    // When Samples per Pixel (0028,0002) is greater than 1,
+    // Photometric Interpretation (0028,0004) shall be RGB for uncompressed or lossless compressed Transfer Syntaxes that do not have defined color space transformations,
+    // YBR_ICT for irreversible JPEG 2000 Transfer Syntaxes,
+    // YBR_RCT for reversible JPEG 2000 Transfer Syntaxes,
+    // YBR_PARTIAL_420 for MPEG2, MPEG-4 AVC/H.264, HEVC/H.265 Transfer Syntaxes and
+    // YBR_FULL_422 for JPEG lossy compressed Transfer Syntaxes.
+    // Note that YBR_FULL is explicitly not permitted for RLE in this SOP class.
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            return (photometricInterpretation == "YBR_ICT");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            return (photometricInterpretation == "YBR_RCT");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            return (photometricInterpretation == "YBR_PARTIAL_420");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            return (photometricInterpretation == "YBR_FULL_422");
+            /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return OFTrue;
+            /* break; */
+        default:
+            return (photometricInterpretation == "RGB");
+            /* break; */
+    }
+}
+
+
+OFCondition I2DOutputPlugOphthalmicPhotography::updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return EC_Normal;
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            if (photometricInterpretation == "YBR_ICT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            if (photometricInterpretation == "YBR_RCT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            if (photometricInterpretation == "YBR_PARTIAL_420") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            // silently replace "YBR_FULL" by "YBR_FULL_422". Most JPEG codecs won't mind.
+            if (photometricInterpretation == "YBR_FULL")
+            {
+                photometricInterpretation = "YBR_FULL_422";
+                return EC_Normal;
+            }
+            else if (photometricInterpretation == "YBR_FULL_422") return EC_Normal;
+            else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return EC_Normal;
+            /* break; */
+        default:
+            if (photometricInterpretation == "RGB") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+    }
+}
+
+
 OFCondition I2DOutputPlugOphthalmicPhotography::insertMultiFrameAttributes(
   DcmDataset* targetDataset,
   size_t numberOfFrames) const
index 51120056ee6861527b294ec3aa69906b7f27206b..b6e1bb493b01ab03e4e8b6426d3fa634ee7090a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2021, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -81,6 +81,19 @@ OFBool I2DOutputPlugSC::supportsMultiframe() const
 }
 
 
+OFBool I2DOutputPlugSC::colorModelPermitted(const OFString& /* photometricInterpretation */, E_TransferSyntax /* outputTS */) const
+{
+    // in secondary capture, no restrictions exist
+    return OFTrue;
+}
+
+
+OFCondition I2DOutputPlugSC::updateColorModel(OFString& /* photometricInterpretation */, E_TransferSyntax /* outputTS */) const
+{
+    return EC_Normal;
+}
+
+
 OFCondition I2DOutputPlugSC::insertMultiFrameAttributes(
   DcmDataset* /* targetDataset */,
   size_t /* numberOfFrames */) const
index f507443209546e91558477effe34b0f1e964aecf..7a0a005dce39a20f72e0b5d711156ae695f3cc63 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -134,6 +134,146 @@ OFBool I2DOutputPlugVLP::supportsMultiframe() const
 }
 
 
+OFBool I2DOutputPlugVLP::colorModelPermitted(const OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return OFTrue;
+
+    // DICOM part 3, C.8.12.1.1.1:
+    // Photometric Interpretation (0028,0004) shall be RGB for uncompressed or lossless compressed Transfer Syntaxes that do not have defined color space transformations,
+    // YBR_ICT for irreversible JPEG 2000 Transfer Syntaxes,
+    // YBR_RCT for reversible JPEG 2000 Transfer Syntaxes,
+    // YBR_PARTIAL_420 for MPEG2, MPEG-4 AVC/H.264, HEVC/H.265 Transfer Syntaxes and
+    // YBR_FULL_422 for JPEG lossy compressed Transfer Syntaxes.
+    // Note that YBR_FULL is explicitly not permitted for RLE in this SOP class.
+
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            return (photometricInterpretation == "YBR_ICT");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            return (photometricInterpretation == "YBR_RCT");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            return (photometricInterpretation == "YBR_PARTIAL_420");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            return (photometricInterpretation == "YBR_FULL_422");
+            /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return OFTrue;
+            /* break; */
+        default:
+            return (photometricInterpretation == "RGB");
+            /* break; */
+    }
+}
+
+
+OFCondition I2DOutputPlugVLP::updateColorModel(OFString& photometricInterpretation, E_TransferSyntax outputTS) const
+{
+    if (photometricInterpretation == "MONOCHROME2") return EC_Normal;
+    switch(outputTS)
+    {
+        case EXS_JPEG2000:
+        case EXS_JPEG2000Multicomponent:
+        case EXS_HighThroughputJPEG2000:
+            if (photometricInterpretation == "YBR_ICT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEG2000LosslessOnly:
+        case EXS_JPEG2000MulticomponentLosslessOnly:
+        case EXS_HighThroughputJPEG2000LosslessOnly:
+        case EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly:
+            if (photometricInterpretation == "YBR_RCT") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_MPEG2MainProfileAtMainLevel:
+        case EXS_FragmentableMPEG2MainProfileMainLevel:
+        case EXS_MPEG2MainProfileAtHighLevel:
+        case EXS_FragmentableMPEG2MainProfileHighLevel:
+        case EXS_MPEG4HighProfileLevel4_1:
+        case EXS_FragmentableMPEG4HighProfileLevel4_1:
+        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1:
+        case EXS_MPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo:
+        case EXS_MPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo:
+        case EXS_MPEG4StereoHighProfileLevel4_2:
+        case EXS_FragmentableMPEG4StereoHighProfileLevel4_2:
+        case EXS_HEVCMainProfileLevel5_1:
+        case EXS_HEVCMain10ProfileLevel5_1:
+            if (photometricInterpretation == "YBR_PARTIAL_420") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEGProcess1:
+        case EXS_JPEGProcess2_4:
+        case EXS_JPEGProcess3_5:
+        case EXS_JPEGProcess6_8:
+        case EXS_JPEGProcess7_9:
+        case EXS_JPEGProcess10_12:
+        case EXS_JPEGProcess11_13:
+        case EXS_JPEGProcess16_18:
+        case EXS_JPEGProcess17_19:
+        case EXS_JPEGProcess20_22:
+        case EXS_JPEGProcess21_23:
+        case EXS_JPEGProcess24_26:
+        case EXS_JPEGProcess25_27:
+            // silently replace "YBR_FULL" by "YBR_FULL_422". Most JPEG codecs won't mind.
+            if (photometricInterpretation == "YBR_FULL")
+            {
+                photometricInterpretation = "YBR_FULL_422";
+                return EC_Normal;
+            }
+            else if (photometricInterpretation == "YBR_FULL_422") return EC_Normal;
+            else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+        case EXS_JPEGXLLossless:
+        case EXS_JPEGXLJPEGRecompression:
+        case EXS_JPEGXL:
+            // DICOM part 3 does not (yet) specify any requirements for this IOD and JPEG-XL.
+            return EC_Normal;
+            /* break; */
+        default:
+            if (photometricInterpretation == "RGB") return EC_Normal; else return makeOFCondition(OFM_dcmdata, 18, OF_error, "Unsupported color model");
+            /* break; */
+    }
+}
+
+
 OFCondition I2DOutputPlugVLP::insertMultiFrameAttributes(
   DcmDataset* /* targetDataset */,
   size_t /* numberOfFrames */) const
index 74e454cbe86b691ba068c57a3ff7a89387de64a7..ddeac9c876f1c88ceccc6c6aa5fa49bccc705777 100644 (file)
@@ -15,6 +15,7 @@ DCMTK_ADD_LIBRARY(dcmdata
   dcdict.cc
   dcdictbi.cc
   dcdirrec.cc
+  dcdocdec.cc
   dcelem.cc
   dcencdoc.cc
   dcerror.cc
@@ -28,6 +29,7 @@ DCMTK_ADD_LIBRARY(dcmdata
   dcistrmz.cc
   dcitem.cc
   dcjson.cc
+  dcjsonrd.cc
   dclist.cc
   dcmatch.cc
   dcmetinf.cc
index 92b7a993d9c69e3dc56ea386846dc79afbfd6574..ce421b0420bf721d220d209a8f4af08b940213af 100644 (file)
@@ -658,6 +658,64 @@ dcdirrec.o: dcdirrec.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcvrol.h ../include/dcmtk/dcmdata/dcvrov.h \
  ../include/dcmtk/dcmdata/cmdlnarg.h ../include/dcmtk/dcmdata/dcspchrs.h \
  ../../ofstd/include/dcmtk/ofstd/ofchrenc.h
+dcdocdec.o: dcdocdec.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcdocdec.h ../include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../include/dcmtk/dcmdata/dcfilefo.h ../include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../include/dcmtk/dcmdata/dcelem.h ../include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
+ ../include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcdeftag.h \
+ ../include/dcmtk/dcmdata/dcuid.h
 dcelem.o: dcelem.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
@@ -1322,10 +1380,107 @@ dcjson.o: dcjson.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofsha256.h \
+ ../include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmdata/dcerror.h
+dcjsonrd.o: dcjsonrd.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmdata/dcjsonrd.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../include/dcmtk/dcmdata/dcdefine.h ../include/dcmtk/dcmdata/dcxfer.h \
+ ../include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofjsmn.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcfilefo.h \
+ ../include/dcmtk/dcmdata/dcsequen.h ../include/dcmtk/dcmdata/dcelem.h \
+ ../include/dcmtk/dcmdata/dcobject.h ../include/dcmtk/dcmdata/dctag.h \
+ ../include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcmetinf.h \
+ ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcswap.h \
+ ../include/dcmtk/dcmdata/dcvrov.h ../include/dcmtk/dcmdata/dcvruv.h
 dclist.o: dclist.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../include/dcmtk/dcmdata/dclist.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
@@ -1977,6 +2132,7 @@ dcpixseq.o: dcpixseq.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofrand.h \
+ ../../ofstd/include/dcmtk/ofstd/ofsha256.h \
  ../include/dcmtk/dcmdata/dcpixseq.h ../include/dcmtk/dcmdata/dcsequen.h \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
@@ -2025,7 +2181,8 @@ dcpixseq.o: dcpixseq.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
  ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcpxitem.h \
  ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcitem.h \
- ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcdeftag.h
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcdeftag.h \
+ ../include/dcmtk/dcmdata/dcjson.h
 dcpxitem.o: dcpxitem.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
@@ -3462,6 +3619,7 @@ dcvrod.o: dcvrod.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmath.h \
  ../include/dcmtk/dcmdata/dcvrod.h ../include/dcmtk/dcmdata/dcvrfd.h \
  ../include/dcmtk/dcmdata/dcelem.h ../include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
@@ -3518,6 +3676,7 @@ dcvrof.o: dcvrof.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmath.h \
  ../include/dcmtk/dcmdata/dcjson.h ../include/dcmtk/dcmdata/dctagkey.h \
  ../include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
index 4dd0b32236e78a7d6ba862aa0e44561203b55f62..41ec5bbb7f950328d8f3d9f61a35b346e002b1f0 100644 (file)
@@ -49,7 +49,7 @@ objs = dcpixseq.o dcpxitem.o dcuid.o dcerror.o dcencdoc.o\
        dcvrut.o dcvrur.o dcvruc.o dctypes.o dcpcache.o dcddirif.o dcistrma.o \
        dcistrmb.o dcistrmf.o dcistrms.o dcistrmz.o dcostrma.o dcostrmb.o \
        dcostrmf.o dcostrms.o dcostrmz.o dcwcache.o dcpath.o vrscan.o vrscanl.o \
-       dcfilter.o dcmatch.o dcjson.o
+       dcfilter.o dcmatch.o dcjson.o dcjsonrd.o dcdocdec.o
 
 support_objs = mkdeftag.o mkdictbi.o
 support_progs = mkdeftag mkdictbi
index 56b17205a2eac49b2dda05615b67879efb5f7e8e..13ae922382177034cef5a4d3b00bd28713b2db72 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2023, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -31,9 +31,7 @@
 #endif
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* for O_BINARY */
-#endif
 END_EXTERN_C
 
 #include "dcmtk/ofstd/ofstd.h"
index ae4a9b636e28fc9f58d9e33f3c053bea17d469bd..73f77375fdb5c2b17a71f63f242a295f696a0bfe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -603,7 +603,7 @@ OFCondition DcmByteString::makeMachineByteString(const Uint32 length)
                 if (realLength > 0)
                 {
                     size_t i = OFstatic_cast(size_t, realLength);
-                    while ((i > 0) && (value[i - 1] == paddingChar))
+                    while ((i > 0) && ((value[i - 1] == paddingChar) || (value[i - 1] == '\0')))
                         value[--i] = '\0';
                     realLength = OFstatic_cast(Uint32, i);
                 }
@@ -639,26 +639,19 @@ Uint8 *DcmByteString::newValueField()
             return NULL;
         }
         /* allocate space for extra padding character (required for the DICOM representation of the string) */
-#ifdef HAVE_STD__NOTHROW
+
         // we want to use a non-throwing new here if available.
         // If the allocation fails, we report an EC_MemoryExhausted error
         // back to the caller.
         value = new (std::nothrow) Uint8[lengthField + 2];
-#else
-        /* make sure that the pointer is set to NULL in case of error */
-        try
-        {
-            value = new Uint8[lengthField + 2];
-        }
-        catch (STD_NAMESPACE bad_alloc const &)
-        {
-            value = NULL;
-        }
-#endif
 
         /* terminate string after real length */
         if (value != NULL)
+        {
             value[lengthField] = 0;
+            value[lengthField+1] = 0;
+        }
+
         /* enforce old (pre DCMTK 3.5.2) behaviour? */
         if (!dcmAcceptOddAttributeLength.get())
         {
@@ -668,22 +661,11 @@ Uint8 *DcmByteString::newValueField()
         }
     } else {
         /* length is even, but we need an extra byte for the terminating 0 byte */
-#ifdef HAVE_STD__NOTHROW
+
         // we want to use a non-throwing new here if available.
         // If the allocation fails, we report an EC_MemoryExhausted error
         // back to the caller.
         value = new (std::nothrow) Uint8[lengthField + 1];
-#else
-        /* make sure that the pointer is set to NULL in case of error */
-        try
-        {
-            value = new Uint8[lengthField + 1];
-        }
-        catch (STD_NAMESPACE bad_alloc const &)
-        {
-            value = NULL;
-        }
-#endif
     }
     /* make sure that the string is properly terminated by a 0 byte */
     if (value != NULL)
index 90c66fd4c9f94a819c6bc64df6ad70044a628cea..a10d49d99e5813633045a6ed379d51a93cbedb01 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -25,7 +25,7 @@
 #include "dcmtk/dcmdata/dcspchrs.h"   /* for class DcmSpecificCharacterSet */
 #include "dcmtk/dcmdata/dcitem.h"     /* for class DcmItem */
 #include "dcmtk/dcmdata/dcdeftag.h"   /* for tag definitions */
-#include "dcmtk/dcmdata/dcjson.h"     /* json helper classes */
+#include "dcmtk/dcmdata/dcjson.h"     /* JSON helper classes */
 #include "dcmtk/dcmdata/dcmatch.h"
 
 //
@@ -224,19 +224,23 @@ OFCondition DcmCharString::getSpecificCharacterSet(OFString &charset)
 OFCondition DcmCharString::writeJson(STD_NAMESPACE ostream &out,
     DcmJsonFormat &format)
 {
+    OFCondition result = EC_Normal;
+
     /* always write JSON Opener */
     DcmElement::writeJsonOpener(out, format);
+
     /* write element value (if non-empty) */
     if (!isEmpty())
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            result = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
+            OFString value;
             OFCondition status = getOFString(value, 0L);
             if (status.bad())
                 return status;
@@ -254,10 +258,10 @@ OFCondition DcmCharString::writeJson(STD_NAMESPACE ostream &out,
             format.printValueSuffix(out);
         }
     }
+
     /* write JSON Closer  */
     DcmElement::writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
index b0ac91bb97cac241e3f478f14a7f93c419f1573c..faf2f600400e5e6c37f415fa60e3eb32c7831747 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2023, OFFIS e.V.
+ *  Copyright (C) 1997-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -518,6 +518,40 @@ OFCondition DcmCodecList::decodeFrame(
 }
 
 
+Uint16 DcmCodecList::decodedBitsAllocated(
+  const DcmXfer & fromType,
+  Uint16 bitsAllocated,
+  Uint16 bitsStored)
+{
+#ifdef WITH_THREADS
+  if (! codecLock.initialized()) return 0; // should never happen
+#endif
+  Uint16 result = 0;
+
+  // acquire write lock on codec list.  Will block if some write lock is currently active.
+#ifdef WITH_THREADS
+  OFReadWriteLocker locker(codecLock);
+  if (0 == locker.rdlock())
+  {
+#endif
+    E_TransferSyntax fromXfer = fromType.getXfer();
+    OFListIterator(DcmCodecList *) first = registeredCodecs.begin();
+    OFListIterator(DcmCodecList *) last = registeredCodecs.end();
+    while (first != last)
+    {
+      if ((*first)->codec->canChangeCoding(fromXfer, EXS_LittleEndianExplicit))
+      {
+        result = (*first)->codec->decodedBitsAllocated(bitsAllocated, bitsStored);
+        first = last;
+      } else ++first;
+    }
+#ifdef WITH_THREADS
+  } else result = 0;
+#endif
+  return result;
+}
+
+
 OFCondition DcmCodecList::encode(
   const E_TransferSyntax fromRepType,
   const DcmRepresentationParameter * fromParam,
index 4ceb4a30d3122ac0f0f6a1197ea6418ad20d787c..9292f139c6157abfbac0d8c9b6a138256b86c93d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -471,11 +471,10 @@ OFCondition DcmDataset::readUntilTag(DcmInputStream &inStream,
 // ********************************
 
 
-OFCondition DcmDataset::write(
-      DcmOutputStream &outStream,
-      const E_TransferSyntax oxfer,
-      const E_EncodingType enctype /* = EET_UndefinedLength */,
-      DcmWriteCache *wcache)
+OFCondition DcmDataset::write(DcmOutputStream &outStream,
+                              const E_TransferSyntax oxfer,
+                              const E_EncodingType enctype /* = EET_UndefinedLength */,
+                              DcmWriteCache *wcache)
 {
     return write(outStream, oxfer, enctype, wcache, EGL_recalcGL);
 }
@@ -919,3 +918,11 @@ OFCondition DcmDataset::doPostReadChecks()
 
   return result;
 }
+
+// ********************************
+
+void DcmDataset::initializeXfer(const E_TransferSyntax xfer)
+{
+  OriginalXfer = xfer;
+  CurrentXfer = xfer;
+}
index b1d300150f8c45753e35fdd4fc2e4f5adf083841..8980771b59fceedb2d10f28577b19ea9826d0e37 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2024, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -655,6 +655,9 @@ OFString DicomDirInterface::recordTypeToName(const E_DirRecType recordType)
         case ERT_Inventory:
             recordName = "Inventory";
             break;
+        case ERT_WfPresentation:
+            recordName = "WfPresentation";
+            break;
         default:
             recordName = "(unknown-directory-record-type)";
             break;
@@ -842,6 +845,11 @@ static E_DirRecType sopClassToRecordType(const OFString &sopClass)
         result = ERT_Annotation;
     else if (compare(sopClass, UID_InventoryStorage))
         result = ERT_Inventory;
+    else if (compare(sopClass, UID_WaveformPresentationStateStorage) ||
+             compare(sopClass, UID_WaveformAcquisitionPresentationStateStorage))
+    {
+        result = ERT_WfPresentation;
+    }
     return result;
 }
 
@@ -1032,6 +1040,7 @@ static OFCondition insertSortedUnder(DcmDirectoryRecord *parent,
             case ERT_Assessment:
             case ERT_Radiotherapy:
             case ERT_Annotation:
+            case ERT_WfPresentation:
                 /* try to insert based on InstanceNumber */
                 result = insertWithISCriterion(parent, child, DCM_InstanceNumber);
                 break;
@@ -1107,6 +1116,8 @@ static OFBool isMultiframeStorageSOPClass(const OFString &sopClassUID)
     return compare(sopClassUID, UID_BreastProjectionXRayImageStorageForPresentation) ||
            compare(sopClassUID, UID_BreastProjectionXRayImageStorageForProcessing) ||
            compare(sopClassUID, UID_BreastTomosynthesisImageStorage) ||
+// in fact, the following IOD is a multi-frame image but the individual frames are rather "tiles"
+//         compare(sopClassUID, UID_ConfocalMicroscopyTiledPyramidalImageStorage) ||
            compare(sopClassUID, UID_EnhancedContinuousRTImageStorage) ||
            compare(sopClassUID, UID_EnhancedCTImageStorage) ||
            compare(sopClassUID, UID_EnhancedMRColorImageStorage) ||
@@ -1116,8 +1127,10 @@ static OFBool isMultiframeStorageSOPClass(const OFString &sopClassUID)
            compare(sopClassUID, UID_EnhancedUSVolumeStorage) ||
            compare(sopClassUID, UID_EnhancedXAImageStorage) ||
            compare(sopClassUID, UID_EnhancedXRFImageStorage) ||
+//         compare(sopClassUID, UID_HeightMapSegmentationStorage) ||
            compare(sopClassUID, UID_IntravascularOpticalCoherenceTomographyImageStorageForPresentation) ||
            compare(sopClassUID, UID_IntravascularOpticalCoherenceTomographyImageStorageForProcessing) ||
+//         compare(sopClassUID, UID_LabelMapSegmentationStorage) ||
            compare(sopClassUID, UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage) ||
            compare(sopClassUID, UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage) ||
            compare(sopClassUID, UID_MultiframeSingleBitSecondaryCaptureImageStorage) ||
@@ -1127,8 +1140,9 @@ static OFBool isMultiframeStorageSOPClass(const OFString &sopClassUID)
            compare(sopClassUID, UID_OphthalmicPhotography16BitImageStorage) ||
            compare(sopClassUID, UID_OphthalmicPhotography8BitImageStorage) ||
            compare(sopClassUID, UID_OphthalmicTomographyImageStorage) ||
-           compare(sopClassUID, UID_ParametricMapStorage) ||
-           compare(sopClassUID, UID_RTDoseStorage) ||
+//         compare(sopClassUID, UID_ParametricMapStorage) ||
+           compare(sopClassUID, UID_PhotoacousticImageStorage) ||
+//         compare(sopClassUID, UID_RTDoseStorage) ||
            compare(sopClassUID, UID_RTImageStorage) ||
            compare(sopClassUID, UID_UltrasoundMultiframeImageStorage) ||
            compare(sopClassUID, UID_VideoEndoscopicImageStorage) ||
@@ -2379,7 +2393,7 @@ OFCondition DicomDirInterface::checkMandatoryAttributes(DcmMetaInfo *metainfo,
         metainfo->findAndGetOFStringArray(DCM_TransferSyntaxUID, transferSyntax);
         metainfo->findAndGetOFStringArray(DCM_MediaStorageSOPClassUID, mediaSOPClassUID);
         E_DirRecType recordType = sopClassToRecordType(mediaSOPClassUID);
-        /* hanging protocol, palette and implant files are handled separately */
+        /* some directory record types are handled separately */
         if (recordType == ERT_HangingProtocol)
         {
             /* check whether all type 1 elements are really present */
@@ -2564,6 +2578,7 @@ OFCondition DicomDirInterface::checkMandatoryAttributes(DcmMetaInfo *metainfo,
                     }
                     break;
                 case ERT_Presentation:
+                case ERT_WfPresentation:
                     if (!checkExistsWithValue(dataset, DCM_InstanceNumber, filename))
                         result = EC_MissingAttribute;
                     if (!checkExistsWithValue(dataset, DCM_ContentLabel, filename))
@@ -2950,6 +2965,7 @@ OFBool DicomDirInterface::recordMatchesDataset(DcmDirectoryRecord *record,
             case ERT_Radiotherapy:
             case ERT_Annotation:
             case ERT_Inventory:
+            case ERT_WfPresentation:
                 /* The attribute ReferencedSOPInstanceUID is automatically
                  * put into a Directory Record when a filename is present.
                 */
@@ -3335,6 +3351,42 @@ DcmDirectoryRecord *DicomDirInterface::buildPresentationRecord(DcmDirectoryRecor
 }
 
 
+// create or update waveform presentation state record and copy required values from dataset
+DcmDirectoryRecord *DicomDirInterface::buildWfPresentationRecord(DcmDirectoryRecord *record,
+                                                                 DcmFileFormat *fileformat,
+                                                                 const OFString &referencedFileID,
+                                                                 const OFFilename &sourceFilename)
+{
+    /* create new waveform presentation record */
+    if (record == NULL)
+        record = new DcmDirectoryRecord(ERT_WfPresentation, referencedFileID.c_str(), sourceFilename, fileformat);
+    if (record != NULL)
+    {
+        /* check whether new record is ok */
+        if (record->error().good())
+        {
+            DcmDataset *dataset = fileformat->getDataset();
+            /* copy attribute values from dataset to waveform presentation record */
+            copyElementType1(dataset, DCM_InstanceNumber, record, sourceFilename);
+            copyElementType1(dataset, DCM_ContentLabel, record, sourceFilename);
+            copyElementType2(dataset, DCM_ContentDescription, record, sourceFilename);
+            copyElementType1(dataset, DCM_PresentationCreationDate, record, sourceFilename);
+            copyElementType1(dataset, DCM_PresentationCreationTime, record, sourceFilename);
+            copyElementType3(dataset, DCM_ContentCreatorName, record, sourceFilename);
+            copyElementType1C(dataset, DCM_ReferencedSeriesSequence, record, sourceFilename);
+            // tbd: need to check content of the referenced series sequence
+        } else {
+            printRecordErrorMessage(record->error(), ERT_WfPresentation, "create");
+            /* free memory */
+            delete record;
+            record = NULL;
+        }
+    } else
+        printRecordErrorMessage(EC_MemoryExhausted, ERT_WfPresentation, "create");
+    return record;
+}
+
+
 // create or update waveform record and copy required values from dataset
 DcmDirectoryRecord *DicomDirInterface::buildWaveformRecord(DcmDirectoryRecord *record,
                                                            DcmFileFormat *fileformat,
@@ -4715,6 +4767,9 @@ DcmDirectoryRecord *DicomDirInterface::addRecord(DcmDirectoryRecord *parent,
                 case ERT_Inventory:
                     record = buildInventoryRecord(record, fileformat, referencedFileID, sourceFilename);
                     break;
+                case ERT_WfPresentation:
+                    record = buildWfPresentationRecord(record, fileformat, referencedFileID, sourceFilename);
+                    break;
                 default:
                     /* it can only be an image */
                     record = buildImageRecord(record, fileformat, referencedFileID, sourceFilename);
@@ -4879,6 +4934,7 @@ void DicomDirInterface::inventMissingInstanceLevelAttributes(DcmDirectoryRecord
                 case ERT_Assessment:
                 case ERT_Radiotherapy:
                 case ERT_Annotation:
+                case ERT_WfPresentation:
                     if (!record->tagExistsWithValue(DCM_InstanceNumber))
                         setDefaultValue(record, DCM_InstanceNumber, AutoInstanceNumber++);
                     break;
index 0390c911ea96e88d10de85bbd7973efee7720ddf..a9b80f1a2a59f4ca5325b358ed7dc53ae40ec96a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -232,7 +232,7 @@ splitFields(const char* line, char* fields[], int maxFields, char splitChar)
     size_t len;
 
     do {
-#ifdef __BORLANDC__
+#ifdef HAVE_CLASSIC_BORLAND_COMPILER
         // Borland Builder expects a non-const argument
         p = strchr(OFconst_cast(char *, line), splitChar);
 #else
index 2bf239d6dbf0080f1c629f1ab0fe2805dac1acd7..def1a9cac56ce1aa8ccb2792adb8b61e2d7ab464 100644 (file)
@@ -4,7 +4,7 @@
 **
 **   User: joergr
 **   Host: thinkpad2
-**   Date: 2024-11-16 10:42:05
+**   Date: 2025-11-21 11:54:35
 **   Prog: /home/joergr/Source/dcmtk-full/public/dcmdata/libsrc/mkdictbi
 **
 **   From: ../data/dicom.dic
@@ -1244,6 +1244,22 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_SQ, "RelatedSeriesSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0008, 0x1301, 0x0008, 0x1301,
+      EVR_SQ, "PrincipalDiagnosisCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0008, 0x1302, 0x0008, 0x1302,
+      EVR_SQ, "PrimaryDiagnosisCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0008, 0x1303, 0x0008, 0x1303,
+      EVR_SQ, "SecondaryDiagnosesCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0008, 0x1304, 0x0008, 0x1304,
+      EVR_SQ, "HistologicalDiagnosesCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0008, 0x2110, 0x0008, 0x2110,
       EVR_CS, "RETIRED_LossyImageCompressionRetired", 1, 1, "DICOM/retired",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -2290,6 +2306,30 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_PN, "PatientName", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0010, 0x0011, 0x0010, 0x0011,
+      EVR_SQ, "PersonNamesToUseSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0012, 0x0010, 0x0012,
+      EVR_LT, "NameToUse", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0013, 0x0010, 0x0013,
+      EVR_UT, "NameToUseComment", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0014, 0x0010, 0x0014,
+      EVR_SQ, "ThirdPersonPronounsSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0015, 0x0010, 0x0015,
+      EVR_SQ, "PronounCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0016, 0x0010, 0x0016,
+      EVR_UT, "PronounComment", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0010, 0x0020, 0x0010, 0x0020,
       EVR_LO, "PatientID", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -2342,6 +2382,34 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_CS, "PatientSex", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0010, 0x0041, 0x0010, 0x0041,
+      EVR_SQ, "GenderIdentitySequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0042, 0x0010, 0x0042,
+      EVR_UT, "SexParametersForClinicalUseCategoryComment", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0043, 0x0010, 0x0043,
+      EVR_SQ, "SexParametersForClinicalUseCategorySequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0044, 0x0010, 0x0044,
+      EVR_SQ, "GenderIdentityCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0045, 0x0010, 0x0045,
+      EVR_UT, "GenderIdentityComment", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0046, 0x0010, 0x0046,
+      EVR_SQ, "SexParametersForClinicalUseCategoryCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0010, 0x0047, 0x0010, 0x0047,
+      EVR_UR, "SexParametersForClinicalUseCategoryReference", 1, -1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0010, 0x0050, 0x0010, 0x0050,
       EVR_SQ, "PatientInsurancePlanCodeSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -2507,13 +2575,17 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
   , { 0x0010, 0x2160, 0x0010, 0x2160,
-      EVR_SH, "EthnicGroup", 1, 1, "DICOM",
+      EVR_SH, "RETIRED_EthnicGroup", 1, 1, "DICOM/retired",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
   , { 0x0010, 0x2161, 0x0010, 0x2161,
       EVR_SQ, "EthnicGroupCodeSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0010, 0x2162, 0x0010, 0x2162,
+      EVR_UC, "EthnicGroups", 1, -1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0010, 0x2180, 0x0010, 0x2180,
       EVR_SH, "Occupation", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -3950,6 +4022,54 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_LO, "ImageQualityIndicatorSize", 1, -1, "DICOM/DICONDE",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0014, 0x4101, 0x0014, 0x4101,
+      EVR_SQ, "WaveDimensionsDefinitionSequence", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4102, 0x0014, 0x4102,
+      EVR_US, "WaveDimensionNumber", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4103, 0x0014, 0x4103,
+      EVR_LO, "WaveDimensionDescription", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4104, 0x0014, 0x4104,
+      EVR_US, "WaveDimensionUnit", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4105, 0x0014, 0x4105,
+      EVR_CS, "WaveDimensionValueType", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4106, 0x0014, 0x4106,
+      EVR_SQ, "WaveDimensionValuesSequence", 1, -1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4107, 0x0014, 0x4107,
+      EVR_US, "ReferencedWaveDimension", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4108, 0x0014, 0x4108,
+      EVR_SL, "IntegerNumericValue", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x4109, 0x0014, 0x4109,
+      EVR_OB, "ByteNumericValue", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x410a, 0x0014, 0x410a,
+      EVR_OW, "ShortNumericValue", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x410b, 0x0014, 0x410b,
+      EVR_OF, "SinglePrecisionFloatingPointNumericValue", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0014, 0x410c, 0x0014, 0x410c,
+      EVR_OD, "DoublePrecisionFloatingPointNumericValue", 1, 1, "DICOM/DICONDE",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0014, 0x5002, 0x0014, 0x5002,
       EVR_IS, "LINACEnergy", 1, 1, "DICOM/DICONDE",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -20394,6 +20514,14 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_DT, "ObservationStartDateTime", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0040, 0xa034, 0x0040, 0xa034,
+      EVR_DT, "EffectiveStartDateTime", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xa035, 0x0040, 0xa035,
+      EVR_DT, "EffectiveStopDateTime", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0040, 0xa040, 0x0040, 0xa040,
       EVR_CS, "ValueType", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -20814,6 +20942,82 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_SQ, "WaveformAnnotationSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0040, 0xb030, 0x0040, 0xb030,
+      EVR_SQ, "StructuredWaveformAnnotationSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb031, 0x0040, 0xb031,
+      EVR_SQ, "WaveformAnnotationDisplaySelectionSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb032, 0x0040, 0xb032,
+      EVR_US, "ReferencedMontageIndex", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb033, 0x0040, 0xb033,
+      EVR_SQ, "WaveformTextualAnnotationSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb034, 0x0040, 0xb034,
+      EVR_DT, "AnnotationDateTime", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb035, 0x0040, 0xb035,
+      EVR_SQ, "DisplayedWaveformSegmentSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb036, 0x0040, 0xb036,
+      EVR_DT, "SegmentDefinitionDateTime", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb037, 0x0040, 0xb037,
+      EVR_SQ, "MontageActivationSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb038, 0x0040, 0xb038,
+      EVR_DS, "MontageActivationTimeOffset", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb039, 0x0040, 0xb039,
+      EVR_SQ, "WaveformMontageSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03a, 0x0040, 0xb03a,
+      EVR_IS, "ReferencedMontageChannelNumber", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03b, 0x0040, 0xb03b,
+      EVR_LT, "MontageName", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03c, 0x0040, 0xb03c,
+      EVR_SQ, "MontageChannelSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03d, 0x0040, 0xb03d,
+      EVR_US, "MontageIndex", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03e, 0x0040, 0xb03e,
+      EVR_IS, "MontageChannelNumber", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb03f, 0x0040, 0xb03f,
+      EVR_LO, "MontageChannelLabel", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb040, 0x0040, 0xb040,
+      EVR_SQ, "MontageChannelSourceCodeSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb041, 0x0040, 0xb041,
+      EVR_SQ, "ContributingChannelSourcesSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x0040, 0xb042, 0x0040, 0xb042,
+      EVR_FL, "ChannelWeight", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0040, 0xdb00, 0x0040, 0xdb00,
       EVR_CS, "TemplateIdentifier", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -21690,6 +21894,10 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_SQ, "OrganizationalRoleCodeSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0044, 0x0110, 0x0044, 0x0110,
+      EVR_SQ, "RTAssertionsSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
 #ifdef ENABLE_PRIVATE_TAGS
   , { 0x0045, 0x0004, 0x0045, 0x0004,
       EVR_CS, "AES", 1, 1, "PrivateTag",
@@ -22546,6 +22754,10 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_UL, "TotalPixelMatrixFocalPlanes", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x0048, 0x0304, 0x0048, 0x0304,
+      EVR_CS, "TilesOverlap", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x0050, 0x0004, 0x0050, 0x0004,
       EVR_CS, "CalibrationImage", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -27432,6 +27644,26 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_DS, "DVHMeanDose", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x3004, 0x0080, 0x3004, 0x0080,
+      EVR_SQ, "DoseCalculationModelSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x3004, 0x0081, 0x3004, 0x0081,
+      EVR_SQ, "DoseCalculationAlgorithmSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x3004, 0x0082, 0x3004, 0x0082,
+      EVR_CS, "CommissioningStatus", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x3004, 0x0083, 0x3004, 0x0083,
+      EVR_SQ, "DoseCalculationModelParameterSequence", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x3004, 0x0084, 0x3004, 0x0084,
+      EVR_CS, "DoseDepositionCalculationMedium", 1, 1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x3006, 0x0002, 0x3006, 0x0002,
       EVR_SH, "StructureSetLabel", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
@@ -29528,6 +29760,14 @@ static const DBI_SimpleEntry simpleBuiltinDict[] = {
       EVR_IS, "NumberOfPaintings", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
       NULL }
+  , { 0x300a, 0x039b, 0x300a, 0x039b,
+      EVR_FL, "ScanSpotGantryAngles", 1, -1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
+  , { 0x300a, 0x039c, 0x300a, 0x039c,
+      EVR_FL, "ScanSpotPatientSupportAngles", 1, -1, "DICOM",
+      DcmDictRange_Unspecified, DcmDictRange_Unspecified,
+      NULL }
   , { 0x300a, 0x03a0, 0x300a, 0x03a0,
       EVR_SQ, "IonToleranceTableSequence", 1, 1, "DICOM",
       DcmDictRange_Unspecified, DcmDictRange_Unspecified,
index c374c347422cf6256894c4ef59d48ecdcf90fcb6..43af8939124280801ea7f4f9de568a8d4b1262fe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -89,7 +89,8 @@ static const char *DRTypeNames[] =
     "ASSESSMENT",
     "RADIOTHERAPY",
     "ANNOTATION",
-    "INVENTORY"
+    "INVENTORY",
+    "WF PRESENTATION"
 };
 
 static const short DIM_OF_DRTypeNames = OFstatic_cast(short, (sizeof(DRTypeNames) / sizeof(DRTypeNames[0])));
@@ -425,6 +426,7 @@ OFCondition DcmDirectoryRecord::checkHierarchy(const E_DirRecType upperRecord,
                 case ERT_Assessment:
                 case ERT_Radiotherapy:
                 case ERT_Annotation:
+                case ERT_WfPresentation:
                 case ERT_Private:
                     l_error = EC_Normal;
                     break;
@@ -524,6 +526,7 @@ OFCondition DcmDirectoryRecord::checkHierarchy(const E_DirRecType upperRecord,
         case ERT_Radiotherapy:
         case ERT_Annotation:
         case ERT_Inventory:
+        case ERT_WfPresentation:
         case ERT_Private:
             switch (lowerRecord)
             {
diff --git a/dcmdata/libsrc/dcdocdec.cc b/dcmdata/libsrc/dcdocdec.cc
new file mode 100644 (file)
index 0000000..10c9d6d
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *
+ *  Copyright (C) 2007-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Marco Eichelberg, Tingyan Xu
+ *
+ *  Purpose: Helper class for extracting encapsulated file from a DICOM encapsulated storage object
+ *
+ */
+
+//make sure OS specific configuration is included first
+#include "dcmtk/config/osconfig.h"
+#include "dcmtk/dcmdata/dcdocdec.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dcuid.h"
+
+BEGIN_EXTERN_C
+#include <fcntl.h>                       /*  for O_BINARY */
+#ifdef HAVE_IO_H
+#include <io.h>                          /* for setmode() on Windows */
+#endif
+END_EXTERN_C
+
+
+DcmDocumentDecapsulator::DcmDocumentDecapsulator()
+: readMode_(ERM_autoDetect)
+, inputXfer_(EXS_Unknown)
+, execString_(NULL)
+, inputFname_(NULL)
+, outputFname_(NULL)
+, dicomFile_()
+{
+}
+
+
+DcmDocumentDecapsulator::~DcmDocumentDecapsulator()
+{
+}
+
+
+OFCondition DcmDocumentDecapsulator::loadDICOMFile()
+{
+    // check filename
+    if ((inputFname_ == NULL) || (strlen(inputFname_) == 0))
+    {
+        DCMDATA_ERROR("invalid input filename: <empty string>");
+        return EC_InvalidFilename;
+    }
+
+    // read DICOM file
+    DCMDATA_INFO("open input file " << inputFname_);
+    OFCondition cond = dicomFile_.loadFile(inputFname_, inputXfer_, EGL_noChange, DCM_MaxReadLength, readMode_);
+    if (cond.bad())
+    {
+        DCMDATA_ERROR(cond.text() << ": reading file: " << inputFname_);
+        return cond;
+    }
+
+    return EC_Normal;
+}
+
+
+OFCondition DcmDocumentDecapsulator::writeEncapsulatedContentToFile()
+{
+    // check filename
+    if ((outputFname_ == NULL) || (strlen(outputFname_) == 0))
+    {
+        DCMDATA_ERROR("invalid output filename: <empty string>");
+        return EC_InvalidFilename;
+    }
+
+    // get encapsulated document
+    DcmDataset* dataset = dicomFile_.getDataset();
+    DcmElement *delem = NULL;
+    OFCondition cond = dataset->findAndGetElement(DCM_EncapsulatedDocument, delem);
+    if (cond.bad() || delem == NULL)
+    {
+        DCMDATA_ERROR("encapsulated document missing");
+        return EC_MissingAttribute;
+    }
+
+    Uint32 len = delem->getLength();
+    Uint8 *encapDocment = NULL;
+    cond = delem->getUint8Array(encapDocment);
+    if (cond.bad() || encapDocment == NULL || len == 0)
+    {
+        DCMDATA_ERROR("encapsulated Document empty or wrong VR");
+        return EC_MissingAttribute;
+    }
+
+    // get and check element encapsulated document length
+    Uint32 lenElem;
+    cond = dataset->findAndGetUint32(DCM_EncapsulatedDocumentLength, lenElem);
+
+    // EncapsulatedDocumentLength Element is invalid or
+    // it does not fit the length of the encapsulated document
+    // (it has to be equal or equal to EncapsulatedDocumentLength -1)
+    if (cond.bad() || (lenElem != len && lenElem != len - 1))
+    {
+        DCMDATA_DEBUG("EncapsulatedDocumentLength missing or invalid, using length of EncapsulatedDocument");
+        lenElem = len;
+
+        // try to retrieve the SOP Class UID, ignore errors
+        OFString sopClass;
+        (void) dataset->findAndGetOFString(DCM_SOPClassUID, sopClass);
+
+        // try to determine if we need to strip a pad byte at the end of the element
+        if (sopClass == UID_EncapsulatedPDFStorage)
+        {
+            // The PDF format expects files to end with %%EOF followed by CR/LF
+            // (although in some cases the CR/LF may be missing or you might only find CR or LF).
+            // If the last character of the file is not a CR or LF, and not the
+            // letter 'F', we assume it is either trailing garbage or a pad byte, and remove it.
+            if (encapDocment[lenElem-1] != 10 && encapDocment[lenElem-1] != 13 && encapDocment[lenElem-1] != 'F')
+            {
+                DCMDATA_DEBUG("removing pad byte at end of encapsulated document");
+                --lenElem;
+            }
+        }
+        else if (sopClass == UID_EncapsulatedCDAStorage)
+        {
+            // CDA documents end with a closing XML tag, optionally followed by whitespace.
+            // If the last character of the file is not a CR ('\r', 13) or LF ('\n', 10), and not the
+            // letter '>', we assume it is either trailing garbage or a pad byte, and remove it.
+            if (encapDocment[lenElem - 1] != '\n' && encapDocment[lenElem - 1] != '\r' && encapDocment[lenElem - 1] != '>')
+            {
+                DCMDATA_DEBUG("removing pad byte at end of encapsulated document");
+                --lenElem;
+            }
+        }
+        else if (sopClass == UID_EncapsulatedSTLStorage || sopClass == UID_EncapsulatedOBJStorage || sopClass == UID_EncapsulatedMTLStorage)
+        {
+            // STL, OBJ and MTL are text formats. We remove a trailing null byte, but nothing else.
+            if (encapDocment[lenElem - 1] == '\0')
+            {
+                DCMDATA_DEBUG("removing pad byte at end of encapsulated document");
+                --lenElem;
+            }
+        }
+        else
+        {
+            DCMDATA_DEBUG("Unknown encapsulated document SOP class, not removing any pad byte");
+        }
+    }
+
+    DCMDATA_INFO( "writing encapsulated document to " << outputFname_);
+
+    if (strcmp(outputFname_, "-") == 0)
+    {
+#ifdef _WIN32
+        // Set "stdout" to binary mode
+        if (setmode(fileno(stdout), O_BINARY) == -1)
+        {
+            DCMDATA_ERROR("Failed to switch stdout to binary mode");
+            return makeOFCondition(OFM_dcmdata, 19, OF_error, "file write error");
+        }
+#endif
+
+        // write encapsulated document to stdout
+        if (lenElem != fwrite(encapDocment, 1, lenElem, stdout))
+        {
+            DCMDATA_ERROR("write error to stdout");
+            return makeOFCondition(OFM_dcmdata, 19, OF_error, "file write error");
+        }
+    }
+    else
+    {
+        // write encapsulated document to file
+        OFFile encapfile;
+        if (!encapfile.fopen(outputFname_, "wb"))
+        {
+            DCMDATA_ERROR("unable to create file " << outputFname_);
+            return makeOFCondition(OFM_dcmdata, 19, OF_error, "file open error");
+        }
+
+        if (lenElem != encapfile.fwrite(encapDocment, 1, lenElem))
+        {
+            DCMDATA_ERROR("write error in file " << outputFname_);
+            (void) encapfile.fclose();
+            return makeOFCondition(OFM_dcmdata, 19, OF_error, "file write error");
+        }
+
+        if (encapfile.fclose())
+        {
+            DCMDATA_ERROR("write error in file " << outputFname_);
+            return makeOFCondition(OFM_dcmdata, 19, OF_error, "file close error");
+        }
+    }
+
+    DCMDATA_INFO( "conversion successful");
+    return EC_Normal;
+}
+
+
+/** Replace all occurrences of pattern in srcstr with substitute and return
+ *  the result as a new OFString variable.
+ *  @param srcstr source string
+ *  @param pattern pattern string to be substituted.
+ *  @param substitute substitute for occurences of pattern in srcstr
+ *  @return string with patterns replaced
+ */
+static OFString replaceChars(const OFString &srcstr, const OFString &pattern, const OFString &substitute)
+{
+    OFString result = srcstr;
+    size_t pos = 0;
+
+    while (pos != OFString_npos)
+    {
+        pos = result.find(pattern, pos);
+
+        if (pos != OFString_npos)
+        {
+            result.replace(pos, pattern.size(), substitute);
+            pos += substitute.size();
+        }
+    }
+
+    return result;
+}
+
+
+#define FILENAME_PLACEHOLDER "#f"
+
+OFCondition DcmDocumentDecapsulator::executeCommand()
+{
+    if (execString_)
+    {
+        OFString cmdStr = replaceChars(execString_, OFString(FILENAME_PLACEHOLDER), outputFname_);
+
+        // Execute command and return result
+        if (system(cmdStr.c_str()) != 0) return EC_CommandLineFailed;
+    }
+    return EC_Normal;
+}
index 3b9cc2bf7e092eda74d18a1991011d9ad3665e82..e5bfc57cd7d2189aaa14e19c18365dc8784119f2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -74,44 +74,21 @@ DcmElement::DcmElement(const DcmElement &elem)
         // is added to the Length for this purpose.
         if (getLengthField() & 1)
         {
-#ifdef HAVE_STD__NOTHROW
             // we want to use a non-throwing new here if available
             // If the allocation fails, we report an EC_MemoryExhausted error
             // back to the caller.
             fValue = new (std::nothrow) Uint8[getLengthField() + 1 + pad];    // protocol error: odd value length
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                fValue = new Uint8[getLengthField() + 1 + pad];    // protocol error: odd value length
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                fValue = NULL;
-            }
-#endif
+
             if (fValue)
                 fValue[getLengthField()] = 0;
             setLengthField(getLengthField() + 1);              // make Length even
         }
         else
         {
-#ifdef HAVE_STD__NOTHROW
             // we want to use a non-throwing new here if available.
             // If the allocation fails, we report an EC_MemoryExhausted error
             // back to the caller.
             fValue = new (std::nothrow) Uint8[getLengthField() + pad];
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                fValue = new Uint8[getLengthField() + pad];
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                fValue = NULL;
-            }
-#endif
         }
 
         if (!fValue)
@@ -133,13 +110,9 @@ DcmElement &DcmElement::operator=(const DcmElement &obj)
 {
   if (this != &obj)
   {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
     // if created with the nothrow version it must also be deleted with
     // the nothrow version else memory error.
     operator delete[] (fValue, std::nothrow);
-#else
-    delete[] fValue;
-#endif
     delete fLoadValue;
     fLoadValue = NULL;
     fValue = NULL;
@@ -159,44 +132,20 @@ DcmElement &DcmElement::operator=(const DcmElement &obj)
 
         if (getLengthField() & 1)
         {
-#ifdef HAVE_STD__NOTHROW
             // we want to use a non-throwing new here if available.
             // If the allocation fails, we report an EC_MemoryExhausted error
             // back to the caller.
             fValue = new (std::nothrow) Uint8[getLengthField() + 1 + pad];    // protocol error: odd value length
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                fValue = new Uint8[getLengthField() + 1 + pad];    // protocol error: odd value length
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                fValue = NULL;
-            }
-#endif
             if (fValue)
                 fValue[getLengthField()] = 0;
             setLengthField(getLengthField() + 1);              // make Length even
         }
         else
         {
-#ifdef HAVE_STD__NOTHROW
             // we want to use a non-throwing new here if available.
             // If the allocation fails, we report an EC_MemoryExhausted error
             // back to the caller.
             fValue = new (std::nothrow) Uint8[getLengthField() + pad];
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                fValue = new Uint8[getLengthField() + pad];
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                fValue = NULL;
-            }
-#endif
         }
 
         if (!fValue)
@@ -256,13 +205,9 @@ OFCondition DcmElement::copyFrom(const DcmObject& rhs)
 
 DcmElement::~DcmElement()
 {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
     // if created with the nothrow version it must also be deleted with
     // the nothrow version else memory error.
     operator delete[] (fValue, std::nothrow);
-#else
-    delete[] fValue;
-#endif
     delete fLoadValue;
 }
 
@@ -273,13 +218,9 @@ DcmElement::~DcmElement()
 OFCondition DcmElement::clear()
 {
     errorFlag = EC_Normal;
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
     // if created with the nothrow version it must also be deleted with
     // the nothrow version else memory error.
     operator delete[] (fValue, std::nothrow);
-#else
-    delete[] fValue;
-#endif
     fValue = NULL;
     delete fLoadValue;
     fLoadValue = NULL;
@@ -358,20 +299,9 @@ OFCondition DcmElement::detachValueField(OFBool copy)
             if (l_error.good())
             {
                 Uint8 * newValue;
-#ifdef HAVE_STD__NOTHROW
                 // we want to use a non-throwing new here if available
                 newValue = new (std::nothrow) Uint8[getLengthField()];
-#else
-                /* make sure that the pointer is set to NULL in case of error */
-                try
-                {
-                    newValue = new Uint8[getLengthField()];
-                }
-                catch (STD_NAMESPACE bad_alloc const &)
-                {
-                    newValue = NULL;
-                }
-#endif
+
                 if (newValue)
                 {
                     memcpy(newValue, fValue, size_t(getLengthField()));
@@ -752,22 +682,12 @@ Uint8 *DcmElement::newValueField()
               return NULL;
         }
         /* create an array of Length+1 bytes */
-#ifdef HAVE_STD__NOTHROW
+
         // we want to use a non-throwing new here if available.
         // If the allocation fails, we report an EC_MemoryExhausted error
         // back to the caller.
         value = new (std::nothrow) Uint8[lengthField + 1];    // protocol error: odd value length
-#else
-        /* make sure that the pointer is set to NULL in case of error */
-        try
-        {
-            value = new Uint8[lengthField + 1];    // protocol error: odd value length
-        }
-        catch (STD_NAMESPACE bad_alloc const &)
-        {
-            value = NULL;
-        }
-#endif
+
         /* if creation was successful, set last byte to 0 (in order to initialize this byte) */
         /* (no value will be assigned to this byte later, since Length was odd) */
         if (value)
@@ -781,22 +701,13 @@ Uint8 *DcmElement::newValueField()
     }
     /* if this element's length is even, create a corresponding array of Length bytes */
     else
-#ifdef HAVE_STD__NOTHROW
+    {
         // we want to use a non-throwing new here if available.
         // If the allocation fails, we report an EC_MemoryExhausted error
         // back to the caller.
         value = new (std::nothrow) Uint8[lengthField];
-#else
-        /* make sure that the pointer is set to NULL in case of error */
-        try
-        {
-            value = new Uint8[lengthField];
-        }
-        catch (STD_NAMESPACE bad_alloc const &)
-        {
-            value = NULL;
-        }
-#endif
+    }
+
     /* if creation was not successful set member error flag correspondingly */
     if (!value)
         errorFlag = EC_MemoryExhausted;
@@ -845,22 +756,12 @@ OFCondition DcmElement::changeValue(const void *value,
             {
                 Uint8 * newValue;
                 // allocate new memory for value
-#ifdef HAVE_STD__NOTHROW
+
                 // we want to use a non-throwing new here if available.
                 // If the allocation fails, we report an EC_MemoryExhausted error
                 // back to the caller.
                 newValue = new (std::nothrow) Uint8[getLengthField() + num];
-#else
-                /* make sure that the pointer is set to NULL in case of error */
-                try
-                {
-                    newValue = new Uint8[getLengthField() + num];
-                }
-                catch (STD_NAMESPACE bad_alloc const &)
-                {
-                    newValue = NULL;
-                }
-#endif
+
                 if (!newValue)
                     errorFlag = EC_MemoryExhausted;
                 if (errorFlag.good())
@@ -873,13 +774,9 @@ OFCondition DcmElement::changeValue(const void *value,
                     memcpy(newValue, fValue, size_t(getLengthField()));
                     // copy value passed as a parameter to the end
                     memcpy(&newValue[getLengthField()], OFstatic_cast(const Uint8 *, value), size_t(num));
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
                     // if created with the nothrow version it must also be deleted with
                     // the nothrow version else memory error.
                     operator delete[] (fValue, std::nothrow);
-#else
-                    delete[] fValue;
-#endif
                     fValue = newValue;
                     setLengthField(getLengthField() + num);
                 } else
@@ -969,6 +866,21 @@ OFCondition DcmElement::putFloat32(const Float32 /*val*/,
 }
 
 
+OFCondition DcmElement::putSint64(const Sint64 /*val*/,
+                                  const unsigned long /*pos*/)
+{
+    errorFlag = EC_IllegalCall;
+    return errorFlag;
+}
+
+
+OFCondition DcmElement::putUint64(const Uint64 /*val*/,
+                                  const unsigned long /*pos*/)
+{
+    errorFlag = EC_IllegalCall;
+    return errorFlag;
+}
+
 OFCondition DcmElement::putFloat64(const Float64 /*val*/,
                                    const unsigned long /*pos*/)
 {
@@ -1033,6 +945,21 @@ OFCondition DcmElement::putFloat32Array(const Float32 * /*val*/,
 }
 
 
+OFCondition DcmElement::putSint64Array(const Sint64 * /*val*/,
+                                       const unsigned long /*num*/)
+{
+    errorFlag = EC_IllegalCall;
+    return errorFlag;
+}
+
+
+OFCondition DcmElement::putUint64Array(const Uint64 * /*val*/,
+                                       const unsigned long /*num*/)
+{
+    errorFlag = EC_IllegalCall;
+    return errorFlag;
+}
+
 OFCondition DcmElement::putFloat64Array(const Float64 * /*val*/,
                                         const unsigned long /*num*/)
 {
@@ -1048,13 +975,9 @@ OFCondition DcmElement::putValue(const void * newValue,
 
     if (fValue)
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
         // if created with the nothrow version it must also be deleted with
         // the nothrow version else memory error.
         operator delete[] (fValue, std::nothrow);
-#else
-        delete[] fValue;
-#endif
     }
     fValue = NULL;
 
@@ -1111,13 +1034,9 @@ OFCondition DcmElement::createEmptyValue(const Uint32 length)
     errorFlag = EC_Normal;
     if (fValue)
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
         // if created with the nothrow version it must also be deleted with
         // the nothrow version else memory error.
         operator delete[] (fValue, std::nothrow);
-#else
-        delete[] fValue;
-#endif
     }
     fValue = NULL;
     if (fLoadValue)
@@ -1213,8 +1132,16 @@ OFCondition DcmElement::read(DcmInputStream &inStream,
 
                     if (fLoadValue)
                     {
-                        offile_off_t skipped = inStream.skip(getLengthField());
-                        if (skipped < OFstatic_cast(offile_off_t, getLengthField()))
+                        /* enforce old (pre DCMTK 3.5.2) behaviour ? */
+                        Uint32 lengthField = getLengthField();
+                        if ((lengthField & 1) && !dcmAcceptOddAttributeLength.get())
+                        {
+                            lengthField++;
+                            setLengthField(lengthField);           // make Length even
+                        }
+
+                        offile_off_t skipped = inStream.skip(lengthField);
+                        if (skipped < OFstatic_cast(offile_off_t, lengthField))
                         {
                             /* If desired, specific parser errors will be ignored */
                             if (dcmIgnoreParsingErrors.get())
@@ -1229,13 +1156,9 @@ OFCondition DcmElement::read(DcmInputStream &inStream,
                     }
                 }
                 /* if there is already a value for this element, delete this value */
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
                 // if created with the nothrow version it must also be deleted with
                 // the nothrow version else memory error.
                 operator delete[] (fValue, std::nothrow);
-#else
-                delete[] fValue;
-#endif
                 /* set the transfer state to ERW_inWork */
                 setTransferState(ERW_inWork);
             }
@@ -1695,19 +1618,23 @@ void DcmElement::writeJsonCloser(STD_NAMESPACE ostream &out,
 OFCondition DcmElement::writeJson(STD_NAMESPACE ostream &out,
                                   DcmJsonFormat &format)
 {
+    OFCondition result = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
+
     /* write element value (if non-empty) */
     if (!isEmpty())
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            result = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
+            OFString value;
             OFCondition status = getOFString(value, 0L);
             if (status.bad())
                 return status;
@@ -1725,10 +1652,10 @@ OFCondition DcmElement::writeJson(STD_NAMESPACE ostream &out,
             format.printValueSuffix(out);
         }
     }
+
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
@@ -1982,13 +1909,9 @@ OFCondition DcmElement::createValueFromTempFile(DcmInputStreamFactory *factory,
 {
     if (factory && !(length & 1))
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
         // if created with the nothrow version it must also be deleted with
         // the nothrow version else memory error.
         operator delete[] (fValue, std::nothrow);
-#else
-        delete[] fValue;
-#endif
         fValue = 0;
         delete fLoadValue;
         fLoadValue = factory;
@@ -2000,6 +1923,17 @@ OFCondition DcmElement::createValueFromTempFile(DcmInputStreamFactory *factory,
 }
 
 
+Uint16 DcmElement::decodedBitsAllocated(
+      Uint16 bitsAllocated,
+      Uint16 bitsStored) const
+{
+  // Note: This method only handles the uncompressed case.
+  // A different implementation is provided in class DcmPixelData.
+  if (bitsStored > bitsAllocated) return 0;
+  return bitsAllocated;
+}
+
+
 // the following macro makes the source code more readable and easier to maintain
 
 #define GET_AND_CHECK_UINT16_VALUE(tag, variable)                                                                   \
@@ -2029,6 +1963,7 @@ OFCondition DcmElement::getUncompressedFrameSize(DcmItem *dataset,
         Uint16 cols = 0;
         Uint16 samplesPerPixel = 0;
         Uint16 bitsAllocated = 0;
+        Uint16 bitsStored = 0;
         Sint32 numberOfFrames = 1;
         OFString photometricInterpretation;
 
@@ -2091,7 +2026,15 @@ OFCondition DcmElement::getUncompressedFrameSize(DcmItem *dataset,
             /* see PS3.3 Table C.7-11c: "Bits Allocated (0028,0100) shall be either 1, or a multiple of 8." */
             else if ((bitsAllocated == 0) || ((bitsAllocated > 1) && (bitsAllocated % 8 != 0)))
                 DCMDATA_WARN("DcmElement: Dubious value (" << bitsAllocated << ") for element BitsAllocated " << DCM_BitsAllocated);
+
+            GET_AND_CHECK_UINT16_VALUE(DCM_BitsStored, bitsStored)
+            else if (bitsStored > bitsAllocated)
+            {
+                DCMDATA_WARN("DcmElement: Dubious value (" << bitsStored << ") for element BitsStored " << DCM_BitsAllocated << " larger than value of BitsAllocated " << DCM_BitsAllocated);
+                result = EC_InvalidValue;
+            }
         }
+
         /* if all checks were passed... */
         if (result.good())
         {
@@ -2129,26 +2072,42 @@ OFCondition DcmElement::getUncompressedFrameSize(DcmItem *dataset,
                    DCMDATA_WARN("DcmElement: failed to compute size of PixelData element");
             }
 
-            /* compute frame size (TODO: check for 32-bit integer overflow?) */
-            if ((bitsAllocated % 8) == 0)
+            // Determine the effective value for Bits Allocated, taking into account compression
+            Uint16 effectiveBitsAllocated = decodedBitsAllocated(bitsAllocated, bitsStored);
+            if (effectiveBitsAllocated == 0)
             {
-                const Uint16 bytesAllocated = bitsAllocated / 8;
-                frameSize = bytesAllocated * rows * cols * samplesPerPixel;
+                DCMDATA_WARN("DcmElement: Encapsulated image with BitsAllocated=" << bitsAllocated << " and BitsStored=" << bitsStored << " cannot be decoded");
+                result = EC_InvalidValue;
             }
             else
             {
-                /* need to split calculation in order to avoid integer overflow for large pixel data */
-                const Uint32 v1 = rows * cols * samplesPerPixel;
-                const Uint32 v2 = (bitsAllocated / 8) * v1;
-                const Uint32 v3 = ((bitsAllocated % 8) * v1 + 7) / 8;
-            //  # old code: frameSize = (bitsAllocated * rows * cols * samplesPerPixel + 7) / 8;
-                frameSize = v2 + v3;
+                /* compute frame size */
+                if ((effectiveBitsAllocated % 8) == 0)
+                {
+                    const Uint16 bytesAllocated = effectiveBitsAllocated / 8;
+                    const Uint32 v1 = rows * cols * samplesPerPixel;
+                    frameSize = bytesAllocated * v1;
+                    if (frameSize / bytesAllocated != v1)
+                    {
+                        DCMDATA_WARN("DcmElement: frame size too large, 32-bit integer overflow");
+                        result = EC_InvalidValue;
+                    }
+                }
+                else
+                {
+                    // Split the calculation in order to avoid integer overflow for large pixel data.
+                    // # old code: frameSize = (effectiveBitsAllocated * rows * cols * samplesPerPixel + 7) / 8;
+                    const Uint32 v1 = rows * cols * samplesPerPixel;
+                    const Uint32 v2 = (effectiveBitsAllocated / 8) * v1;
+                    const Uint32 v3 = ((effectiveBitsAllocated % 8) * v1 + 7) / 8;
+                    frameSize = v2 + v3;
+                }
             }
-        } else {
-            /* in case of error, return a frame size of 0 */
-            frameSize = 0;
         }
     }
+
+    /* in case of error, return a frame size of 0 */
+    if (result.bad()) frameSize = 0;
     return result;
 }
 
index e9073064c470384ec443cece44ba342e3d56fee0..4bcf0b69924a0d420ff5f68b851128f41d019c18 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2024, OFFIS e.V.
+ *  Copyright (C) 2018-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -13,7 +13,7 @@
  *
  *  Module:  dcmdata
  *
- *  Author:  Pedro ArizpeGomez
+ *  Author:  Pedro ArizpeGomez, Marco Eichelberg
  *
  *  Purpose: Implementation of Document encapsulation
  *
 #define SHORTCOL 3
 #define LONGCOL 21
 
-// exit codes for this command line tool
-// (common codes are defined in "ofexit.h" included from "ofconapp.h")
-
-// general errors
-#define EXITCODE_MEMORY_EXHAUSTED                4
-
-DcmEncapsulatedDocument::DcmEncapsulatedDocument() :
-        opt_patientBirthdate(),
-        opt_patientID(),
-        opt_patientName(),
-        opt_patientSex(),
-
-        opt_conceptCM(),
-        opt_conceptCSD(),
-        opt_conceptCV(),
-
-        opt_documentTitle(),
-        opt_seriesFile(),
-        opt_seriesUID(),
-        opt_studyUID(),
-
-        opt_oenctype(EET_ExplicitLength),
-        opt_writeMode(EWM_fileformat),
-        opt_oglenc(EGL_withoutGL),
-        opt_opadenc(EPD_withoutPadding),
-        opt_oxfer(EXS_LittleEndianExplicit),
-        opt_filepad(0),
-        opt_itempad(0),
-
-        opt_readSeriesInfo(OFFalse),
-        opt_annotation(OFTrue),
-        opt_increment(OFFalse),
-
-        opt_instance(1),
-        opt_overrideKeys(),
-
-        cda_mediaTypes(),
-        hl7_InstanceIdentifier(),
-        opt_override(OFFalse),
-        // Frame of Reference Module (STL)
-        opt_frameOfReferenceUID(),
-        opt_positionReferenceIndicator(),
-        // Frame of Reference Module (STL)
-        opt_manufacturer(),
-        opt_manufacturerModelName(),
-        opt_deviceSerialNumber(),
-        opt_softwareVersions(),
-        // Enhanced General Equipment Module (STL)
-        opt_measurementUnitsCM(),
-        opt_measurementUnitsCSD(),
-        opt_measurementUnitsCV(),
-        //encapsulation file type
-        ftype()
+DcmEncapsulatedDocument::DcmEncapsulatedDocument()
+: patientBirthdate_()
+, patientID_()
+, patientName_()
+, patientSex_()
+, conceptCM_()
+, conceptCSD_()
+, conceptCV_()
+, documentTitle_()
+, seriesFile_()
+, seriesUID_()
+, studyUID_()
+, specificCharSet_()
+, modality_()
+, oenctype_(EET_ExplicitLength)
+, writeMode_(EWM_fileformat)
+, oglenc_(EGL_withoutGL)
+, opadenc_(EPD_withoutPadding)
+, oxfer_(EXS_LittleEndianExplicit)
+, filepad_(0)
+, itempad_(0)
+, readSeriesInfo_(OFFalse)
+, annotation_(OFTrue)
+, increment_(OFFalse)
+, instance_(1)
+, overrideKeys_()
+, cda_mediaTypes()
+, hl7_InstanceIdentifier()
+, override_(OFFalse)
+, frameOfReferenceUID_()
+, positionReferenceIndicator_()
+, manufacturer_()
+, manufacturerModelName_()
+, deviceSerialNumber_()
+, softwareVersions_()
+, measurementUnitsCM_()
+, measurementUnitsCSD_()
+, measurementUnitsCV_()
+, ftype_(DT_unknownDocument)
+, dfile_()
 {
 }
 
-OFBool DcmEncapsulatedDocument::XMLsearchAttribute(
+
+DcmEncapsulatedDocument::~DcmEncapsulatedDocument()
+{
+}
+
+// ========== static helper functions for processing CDA documents ==========
+
+/** Recursive function used by getAttributeValues to get all occurrences of an attribute as a list.
+ *  @param currnode the current XML node to be processed.
+ *  @param list of strings to which the results are added.
+ *  @param attr the attribute to search for.
+ *  @return OFTrue if the attribute value was found, OFFalse otherwise.
+ */
+static OFBool XMLsearchAttribute(
         XMLNode currnode,
-        OFList<OFString> *results,
-        OFString attr)
+        OFList<OFString> &results,
+        const OFString& attr)
 {
   OFBool found = OFFalse;
 #ifndef _XMLWIDECHAR
   if (currnode.nChildNode() == 0)
   {
-    //"currnode has no children (leaf)";
+    // currnode has no children (leaf)
     if (currnode.isAttributeSet(attr.c_str()))
     {
       //attribute found on leaf
-      results->push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str())));
+      results.push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str())));
       found = OFTrue;
     }
   }
   else
   {
-    //"currnode has children (branch)";
+    // currnode has children (branch)
     if (currnode.isAttributeSet(attr.c_str()))
     {
       //attribute found on branch
-      results->push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str())));
+      results.push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str())));
       found = OFTrue;
     }
     for (int i = 0; i < currnode.nChildNode(); i++)
     {
       //search all children recursively
-      OFBool childfound = XMLsearchAttribute(currnode.getChildNode(i), results, attr);
-      found |= childfound;
+      found |= XMLsearchAttribute(currnode.getChildNode(i), results, attr);
     }
   }
 #endif
   return found;
 }
 
-OFString DcmEncapsulatedDocument::XMLgetAllAttributeValues(
-        XMLNode fileNode,
-        OFString attr)
+
+/** Retrieve all entries of an attribute and returns them as a string, separated by backslashes.
+ *  @param fileNode the root XML node.
+ *  @param attr the attribute to search for.
+ *  @return OFstring containing all entries found, separated by backslashes
+ */
+static OFString XMLgetAllAttributeValues(XMLNode& fileNode, const OFString& attr)
 {
   OFString attributeValues;
 #ifndef _XMLWIDECHAR
   OFList<OFString> attributeValueslist;
-  if (XMLsearchAttribute(fileNode, &attributeValueslist, attr))
+  if (XMLsearchAttribute(fileNode, attributeValueslist, attr))
   {
-    //If the Attribute is mediaType, initialize with text/xml to exclude
-    //the primary MIME Type of the encapsulated document
+    // If the Attribute is mediaType, initialize with text/xml to exclude
+    // the primary MIME Type of the encapsulated document
     if (attr == "mediaType") attributeValues.append("text/xml");
+
     while (!attributeValueslist.empty())
     {
       if (attributeValues.find(attributeValueslist.front()) == OFString_npos)
@@ -154,8 +158,8 @@ OFString DcmEncapsulatedDocument::XMLgetAllAttributeValues(
       }
       attributeValueslist.pop_front();
     }
-    //remove the primary MIME Type of the
-    //encapsulated document
+
+    // remove the primary MIME Type of the encapsulated document
     if (attr == "mediaType")
     {
       if (attributeValues.size() > 9)
@@ -168,682 +172,642 @@ OFString DcmEncapsulatedDocument::XMLgetAllAttributeValues(
   return attributeValues;
 }
 
-OFString DcmEncapsulatedDocument::XMLgetAttribute(
-        XMLNode fileNode,
-        DcmTagKey attr)
+
+/** Retrieve the value from the CDA document corresponding to the given DICOM Tag,
+ *  according to DICOM Part 20, section A.8.
+ *  @param fileNode the root XML node.
+ *  @param attr the tag to search for in the CDA file.
+ *  @return OFstring containing the value of the corresponding tag.
+ */
+static OFString XMLgetAttribute(XMLNode& fileNode, const DcmTagKey& attr)
 {
-  OFString result = "";
 #ifndef _XMLWIDECHAR
-  if (attr == DCM_DocumentTitle)
-  {
-    if (fileNode.getChildNode("title").getText() != NULL)
+    if (attr == DCM_DocumentTitle)
     {
-      result = OFString(OFSTRING_GUARD(fileNode.getChildNode("title").getText()));
+      if (fileNode.getChildNode("title").getText() != NULL)
+      {
+        return OFString(OFSTRING_GUARD(fileNode.getChildNode("title").getText()));
+      }
     }
-  }
-  if (attr == DCM_HL7InstanceIdentifier)
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("root"))) + "^"
-             + OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("extension")));
-  }
-  /*PatientNameExtension could reflect the type of name (PHON, IDE, ABC)
-  if (attr == DCM_PatientNameExtension)
-  {
-  result = OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getAttribute("use")));
-  }*/
-  if (attr == DCM_PatientName)
-  {
-    result = OFString(
-            OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/family").getText())) + "^"
-             + OFString(OFSTRING_GUARD(
-                                fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode(
-                                        "given", 0).getText())) + "^"
-             + OFString(OFSTRING_GUARD(
-                                fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode(
-                                        "given", 1).getText())) + "^"
-             + OFString(
-            OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/prefix").getText())) + "^"
-             + OFString(
-            OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/suffix").getText()));
-  }
-  if (attr == DCM_PatientSex)
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath(
-            "recordTarget/patientRole/patient/administrativeGenderCode").getAttribute("code")));
-  }
-  if (attr == DCM_PatientBirthDate)
-  {
-    result = OFString(OFSTRING_GUARD(
-                              fileNode.getChildNodeByPath("recordTarget/patientRole/patient/birthTime").getAttribute(
-                                      "value")));
-  }
-  //Table A.8-1. Basic Code Attributes Mapping to HL7 V3 Code Data Types (CV, CS, CE and CD)
-  if (attr == DCM_PatientID)
-  {
-    result = OFString(
-            OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/id").getAttribute("extension")));
-  }
-  if (attr == DCM_CodeValue)//Code Value
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("code")));
-  }
-  if (attr == DCM_CodingSchemeUID)//Coding Scheme UID (PS3.16)
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystem")));
-  }
-  if (attr == DCM_CodingSchemeDesignator)//Coding Scheme Designator (0008,0102)
-  {
-    OFString CSDtemp = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemName")));
-    // Abbreviate most common CSNs
-    if (CSDtemp == OFString("LOINC"))
+
+    if (attr == DCM_HL7InstanceIdentifier)
     {
-      result = OFString("LN");
+      return OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("root"))) + "^"
+               + OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("extension")));
     }
-    else
+
+    if (attr == DCM_PatientName)
+    {
+      return OFString(
+              OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/family").getText())) + "^"
+               + OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode("given", 0).getText())) + "^"
+               + OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode("given", 1).getText())) + "^"
+               + OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/prefix").getText())) + "^"
+               + OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/suffix").getText()));
+    }
+
+    if (attr == DCM_PatientSex)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/administrativeGenderCode").getAttribute("code")));
+    }
+
+    if (attr == DCM_PatientBirthDate)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/birthTime").getAttribute("value")));
+    }
+
+    //Table A.8-1. Basic Code Attributes Mapping to HL7 V3 Code Data Types (CV, CS, CE and CD)
+    if (attr == DCM_PatientID)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/id").getAttribute("extension")));
+    }
+
+    if (attr == DCM_CodeValue)
     {
-      if (CSDtemp == OFString("DICOM"))
+      return OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("code")));
+    }
+    if (attr == DCM_CodingSchemeUID)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystem")));
+    }
+    if (attr == DCM_CodingSchemeDesignator)
+    {
+      OFString CSDtemp = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemName")));
+
+      // Abbreviate most common CSNs
+      if (CSDtemp == OFString("LOINC"))
       {
-        result = OFString("DC");
+        return OFString("LN");
       }
       else
       {
-        if (CSDtemp == OFString("SNOMED"))
+        if (CSDtemp == OFString("DICOM"))
         {
-          result = OFString("SRT");
+          return OFString("DCM");
         }
         else
         {
-          result = CSDtemp;
+          if (CSDtemp == OFString("SNOMED"))
+          {
+            return OFString("SCT");
+          }
+          else
+          {
+            return CSDtemp;
+          }
         }
       }
     }
-  }
-  if (attr == DCM_CodingSchemeVersion)//Coding Scheme Version (0008,0103)
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemVersion")));
-  }
-  if (attr == DCM_CodeMeaning)//Code Meaning (0008,0104)
-  {
-    result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("displayName")));
-  }
+
+    if (attr == DCM_CodingSchemeVersion)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemVersion")));
+    }
+
+    if (attr == DCM_CodeMeaning)
+    {
+      return OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("displayName")));
+    }
+
+    // this shouldn't happen
+    DCMDATA_ERROR("XMLgetAttribute called with unsupported attribute tag " << attr);
 #endif
-  return result;
+
+    return "";
 }
 
-int DcmEncapsulatedDocument::getCDAData(
-        const char *filename,
-        OFLogger &appLogger)
+// ========== class methods ==========
+
+OFCondition DcmEncapsulatedDocument::getCDAData()
 {
 #ifdef _XMLWIDECHAR
 #ifdef _MSC_VER
-#pragma message("DCMTK compiled with 'wide char XML parser'. cda2dcm will be unable to read and encapsulate CDA documents.")
+#pragma message("DCMTK compiled with 'wide char XML parser'. dcmencap will be unable to read and encapsulate CDA documents.")
 #else
-#warning "DCMTK compiled with 'wide char XML parser'. cda2dcm will be unable to read and encapsulate CDA documents."
+#warning "DCMTK compiled with 'wide char XML parser'. dcmencap will be unable to read and encapsulate CDA documents."
 #endif
-  OFLOG_ERROR(appLogger, "DCMTK compiled with \"wide char XML parser\". Cannot parse CDA data because of incompatible API.");
-  return 99;
+    DCMDATA_ERROR("DCMTK compiled with \"wide char XML parser\". Cannot parse CDA data because of incompatible API.");
+    return EC_XMLParseError;
 #else
-  if (ftype != "cda")
-  {
-    OFLOG_WARN(appLogger, "Filetype mismatch or filetype not set. Current ftype is " << ftype);
-  }
-  XMLResults err;
-  XMLNode fileNode = XMLNode::parseFile(filename, "ClinicalDocument", &err);
-  OFLOG_TRACE(appLogger, "checking if the XML file is correctly formatted");
-  if (0 != err.error)
-  {
-    OFLOG_ERROR(appLogger, fileNode.getError(err.error));
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  else
-  {
-    OFLOG_TRACE(appLogger, "XML file is correctly formatted");
-  }
-  OFLOG_TRACE(appLogger, "Getting all media types from CDA file");
-  cda_mediaTypes = XMLgetAllAttributeValues(fileNode, "mediaType");
-  OFLOG_TRACE(appLogger, "Following mediaTypes were found: " << cda_mediaTypes);
-  OFLOG_TRACE(appLogger, "Getting HL7 Instance Identifier from CDA file");
-  hl7_InstanceIdentifier = XMLgetAttribute(fileNode, DCM_HL7InstanceIdentifier);
-  OFLOG_TRACE(appLogger, "Reading and comparing patient information between CDA File and options");
-  OFString pID = XMLgetAttribute(fileNode, DCM_PatientID);
-  if ((pID != "") && (opt_patientID != pID))
-  {
-    if (opt_patientID != "")
+    DCMDATA_INFO("Extracting information from CDA document content");
+
+    XMLResults err;
+    XMLNode fileNode = XMLNode::parseFile(ifname_.c_str(), "ClinicalDocument", &err);
+    DCMDATA_TRACE("checking if the XML file is correctly formatted");
+    if (0 != err.error)
     {
-      //if no-override option is inactive, return an error
-      if (!opt_override)
-      {
-        OFLOG_ERROR(appLogger, "Patient ID mismatch:" << OFendl
-                << "Found in the CDA file : " << pID << OFendl
-                << "Entered (or found in DCM file): " << opt_patientID << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
-      {
-        OFLOG_WARN(appLogger, "Patient ID mismatch:" << OFendl
-                << "Found in the CDA file : " << pID << OFendl
-                << "Provided (in DCM file): " << opt_patientID);
-      }
+      DCMDATA_ERROR(fileNode.getError(err.error));
+      return EC_XMLParseError;
     }
     else
     {
-      opt_patientID = pID;
+      DCMDATA_TRACE("XML file is correctly formatted");
     }
-  }
-  OFString pBirthDate = XMLgetAttribute(fileNode, DCM_PatientBirthDate);
-  if ((pBirthDate != "") && (opt_patientBirthdate != pBirthDate))
-  {
-    if (opt_patientBirthdate != "")
+    DCMDATA_TRACE("Getting all media types from CDA file");
+    cda_mediaTypes = XMLgetAllAttributeValues(fileNode, "mediaType");
+    DCMDATA_TRACE("Following mediaTypes were found: " << cda_mediaTypes);
+    DCMDATA_TRACE("Getting HL7 Instance Identifier from CDA file");
+    hl7_InstanceIdentifier = XMLgetAttribute(fileNode, DCM_HL7InstanceIdentifier);
+    DCMDATA_TRACE("Reading and comparing patient information between CDA File and options");
+    OFString pID = XMLgetAttribute(fileNode, DCM_PatientID);
+    if ((pID.length() > 0) && (patientID_ != pID))
     {
-      if (!opt_override)
+      if (patientID_.length() > 0)
       {
-        OFLOG_ERROR(appLogger, "Patient Birth Date mismatch:" << OFendl
-                << "Found in the CDA file : " << pBirthDate << OFendl
-                << "Provided (in DCM file): " << opt_patientBirthdate << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
+        if (override_) DCMDATA_WARN("Patient ID mismatch: '" << pID << "' in CDA, '" << patientID_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("Patient ID mismatch: '" << pID << "' in CDA, '" << patientID_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
       else
       {
-        OFLOG_WARN(appLogger, "Patient Birth Date mismatch:" << OFendl
-                << "Found in the CDA file : " << pBirthDate << OFendl
-                << "Provided (in DCM file): " << opt_patientBirthdate);
+        patientID_ = pID;
       }
     }
-    else opt_patientBirthdate = pBirthDate;
-  }
-  OFString pSex = XMLgetAttribute(fileNode, DCM_PatientSex);
-  if ((pSex != "") && (opt_patientSex != pSex))
-  {
-    if (opt_patientSex != "")
+    OFString pBirthDate = XMLgetAttribute(fileNode, DCM_PatientBirthDate);
+    if ((pBirthDate.length() > 0) && (patientBirthdate_ != pBirthDate))
     {
-      if (!opt_override)
-      {
-        OFLOG_ERROR(appLogger, "Patient Sex mismatch:" << OFendl
-                << "Found in the CDA file : " << pSex << OFendl
-                << "Provided (in DCM file): " << opt_patientSex << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
+      if (patientBirthdate_.length() > 0)
       {
-        OFLOG_WARN(appLogger, "Patient Sex mismatch:" << OFendl
-                << "Found in the CDA file : " << pSex << OFendl
-                << "Provided (in DCM file): " << opt_patientSex);
+        if (override_) DCMDATA_WARN("Patient Birth Date mismatch: '" << pBirthDate << "' in CDA, '" << patientBirthdate_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("Patient Birth Date mismatch: '" << pBirthDate << "' in CDA, '" << patientBirthdate_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else patientBirthdate_ = pBirthDate;
     }
-    else opt_patientSex = pSex;
-  }
-  OFString pName = XMLgetAttribute(fileNode, DCM_PatientName);
-  if ((pName != "^^^^") && (opt_patientName != pName))
-  {
-    if (opt_patientName != "")
+    OFString pSex = XMLgetAttribute(fileNode, DCM_PatientSex);
+    if ((pSex.length() > 0) && (patientSex_ != pSex))
     {
-      if (!opt_override)
-      {
-        OFLOG_ERROR(appLogger, "Patient Name mismatch:" << OFendl
-                << "Found in the CDA file : " << pName << OFendl
-                << "Provided (in DCM file): " << opt_patientName << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
+      if (patientSex_.length() > 0)
       {
-        OFLOG_WARN(appLogger, "Patient Name mismatch:" << OFendl
-                << "Found in the CDA file : " << pName << OFendl
-                << "Provided (in DCM file): " << opt_patientName);
+        if (override_) DCMDATA_WARN("Patient Sex mismatch: '" << pSex << "' in CDA, '" << patientSex_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("Patient Sex mismatch: '" << pSex << "' in CDA, '" << patientSex_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else patientSex_ = pSex;
     }
-    else opt_patientName = pName;
-  }
-  //get document title from CDA
-  OFString dTitle = XMLgetAttribute(fileNode, DCM_DocumentTitle);
-  if (opt_documentTitle == "")
-  {
-    if (opt_conceptCSD != "") opt_documentTitle = opt_conceptCSD;
-    if (opt_conceptCV != "") opt_documentTitle = opt_conceptCV;
-    if (opt_conceptCM != "") opt_documentTitle = opt_conceptCM;
-  }
-
-  if ((dTitle != "") && (opt_documentTitle != dTitle))
-  {
-    if (opt_documentTitle != "")
+    OFString pName = XMLgetAttribute(fileNode, DCM_PatientName);
+    if ((pName != "^^^^") && (patientName_ != pName))
     {
-      if (!opt_override)
+      if (patientName_.length() > 0)
       {
-        OFLOG_ERROR(appLogger, "Document Title mismatch:" << OFendl
-                << "Found in the CDA file : " << dTitle << OFendl
-                << "Provided (in DCM file): " << opt_documentTitle << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
-      {
-        OFLOG_WARN(appLogger, "Document Title mismatch:" << OFendl
-                << "Found in the CDA file : " << dTitle << OFendl
-                << "Provided (in DCM file): " << opt_documentTitle);
+        if (override_) DCMDATA_WARN("Patient Name mismatch: '" << pName << "' in CDA, '" << patientName_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("Patient Name mismatch: '" << pName << "' in CDA, '" << patientName_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else patientName_ = pName;
     }
-    else opt_documentTitle = dTitle;
-  }
-  //get Concept information from CDA
-  OFString cCSD = XMLgetAttribute(fileNode, DCM_CodingSchemeDesignator);
-  if ((cCSD != "") && (opt_conceptCSD != cCSD))
-  {
-    if (opt_conceptCSD != "")
+    //get document title from CDA
+    OFString dTitle = XMLgetAttribute(fileNode, DCM_DocumentTitle);
+    if ((dTitle.length() > 0) && (documentTitle_ != dTitle))
     {
-      if (!opt_override)
+      if (documentTitle_.length() > 0)
       {
-        OFLOG_ERROR(appLogger, "concept CSD mismatch:" << OFendl
-                << "Found in the CDA file : " << cCSD << OFendl
-                << "Provided (in DCM file): " << opt_conceptCSD << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
-      {
-        OFLOG_WARN(appLogger, "concept CSD mismatch:" << OFendl
-                << "Found in the CDA file : " << cCSD << OFendl
-                << "Provided (in DCM file): " << opt_conceptCSD);
+        if (override_) DCMDATA_WARN("Document Title mismatch: '" << dTitle << "' in CDA, '" << documentTitle_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("Document Title mismatch: '" << dTitle << "' in CDA, '" << documentTitle_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else documentTitle_ = dTitle;
     }
-    else opt_conceptCSD = cCSD;
-  }
-  OFString cCV = XMLgetAttribute(fileNode, DCM_CodeValue);
-  if ((cCV != "") && (opt_conceptCV != cCV))
-  {
-    if (opt_conceptCV != "")
+
+    //get Concept information from CDA
+    OFString cCSD = XMLgetAttribute(fileNode, DCM_CodingSchemeDesignator);
+    if ((cCSD.length() > 0) && (conceptCSD_ != cCSD))
     {
-      if (!opt_override)
-      {
-        OFLOG_ERROR(appLogger, "concept CV mismatch:" << OFendl
-                << "Found in the CDA file : " << cCV << OFendl
-                << "Provided (in DCM file): " << opt_conceptCV << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
-      }
-      else
+      if (conceptCSD_.length() > 0)
       {
-        OFLOG_WARN(appLogger, "concept CV mismatch:" << OFendl
-                << "Found in the CDA file : " << cCV << OFendl
-                << "Provided (in DCM file): " << opt_conceptCV);
+        if (override_) DCMDATA_WARN("concept CSD mismatch: '" << cCSD << "' in CDA, '" << conceptCSD_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("concept CSD mismatch: '" << cCSD << "' in CDA, '" << conceptCSD_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else conceptCSD_ = cCSD;
     }
-    else opt_conceptCV = cCV;
-  }
-  OFString cCM = XMLgetAttribute(fileNode, DCM_CodeMeaning);
-  if ((cCM != "") && (opt_conceptCM != cCM))
-  {
-    if (opt_conceptCM != "")
+    OFString cCV = XMLgetAttribute(fileNode, DCM_CodeValue);
+    if ((cCV.length() > 0) && (conceptCV_ != cCV))
     {
-      if (!opt_override)
+      if (conceptCV_.length() > 0)
       {
-        OFLOG_ERROR(appLogger, "concept CM mismatch:" << OFendl
-                << "Found in the CDA file : " << cCM << OFendl
-                << "Provided (in DCM file): " << opt_conceptCM << OFendl
-                << "If you wish to override, run again with +ov");
-        return EXITCODE_COMMANDLINE_SYNTAX_ERROR;
+        if (override_) DCMDATA_WARN("concept CV mismatch: '" << cCV << "' in CDA, '" << conceptCV_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("concept CV mismatch: '" << cCV << "' in CDA, '" << conceptCV_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
-      else
+      else conceptCV_ = cCV;
+    }
+    OFString cCM = XMLgetAttribute(fileNode, DCM_CodeMeaning);
+    if ((cCM.length() > 0) && (conceptCM_ != cCM))
+    {
+      if (conceptCM_.length() > 0)
       {
-        OFLOG_WARN(appLogger, "concept CM mismatch:" << OFendl
-                << "Found in the CDA file : " << cCM << OFendl
-                << "Provided (in DCM file): " << opt_conceptCM);
+        if (override_) DCMDATA_WARN("concept CM mismatch: '" << cCM << "' in CDA, '" << conceptCM_ << "' in DICOM file or specified via command line.");
+        else
+        {
+          DCMDATA_ERROR("concept CM mismatch: '" << cCM << "' in CDA, '" << conceptCM_ << "' in DICOM file or specified via command line.");
+          return EC_InvalidValue;
+        }
       }
+      else conceptCM_ = cCM;
     }
-    else opt_conceptCM = cCM;
-  }
-  return EXITCODE_NO_ERROR;
+    return EC_Normal;
 #endif
 }
 
-void DcmEncapsulatedDocument::addCDACommandlineOptions(OFCommandLine &cmd)
-{
-  ftype = "cda";
-  cmd.setOptionColumns(LONGCOL, SHORTCOL);
-  cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
-  cmd.addParam("cdafile-in", "CDA input filename to be converted");
-  cmd.addParam("dcmfile-out", "DICOM output filename (\"-\" for stdout)");
-  addGeneralOptions(cmd);
-  addDocumentOptions(cmd);
-  cmd.addSubGroup("override CDA data:");
-  cmd.addOption("--no-override", "-ov",
-                "CDA patient and document data must match study,\nseries or manually entered information (default)");
-  cmd.addOption("--override", "+ov",
-                "CDA's data will be overwritten by study, series\nor manually entered information");
-  addOutputOptions(cmd);
-}
 
-void DcmEncapsulatedDocument::addPDFCommandlineOptions(OFCommandLine &cmd)
+static void addGeneralOptions(OFCommandLine &cmd)
 {
-  ftype = "pdf";
-  cmd.setOptionColumns(LONGCOL, SHORTCOL);
-  cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
-  cmd.addParam("pdffile-in", "PDF input filename to be converted");
-  cmd.addParam("dcmfile-out", "DICOM output filename (\"-\" for stdout)");
-  addGeneralOptions(cmd);
-  addDocumentOptions(cmd);
-  addOutputOptions(cmd);
+    cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
+    cmd.addOption("--help", "-h", "print this help text and exit", OFCommandLine::AF_Exclusive);
+    cmd.addOption("--version", "print version information and exit", OFCommandLine::AF_Exclusive);
+    OFLog::addOptions(cmd);
 }
 
-void DcmEncapsulatedDocument::addSTLCommandlineOptions(OFCommandLine &cmd)
-{
-  ftype = "stl";
-  cmd.setOptionColumns(LONGCOL, SHORTCOL);
-  cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
-  cmd.addParam("stlfile-in", "STL input filename to be converted");
-  cmd.addParam("dcmfile-out", "DICOM output filename (\"-\" for stdout)");
-  addGeneralOptions(cmd);
-  addDocumentOptions(cmd);
-  cmd.addSubGroup("enhanced general equipment:");
-  cmd.addOption("--manufacturer", "+mn", 1, "[n]ame: string",
-                "manufacturer's name");
-  cmd.addOption("--manufacturer-model", "+mm", 1, "[n]ame: string",
-                "manufacturer's model name");
-  cmd.addOption("--device-serial", "+ds", 1, "[n]umber: string",
-                "device serial number");
-  cmd.addOption("--software-versions", "+sv", 1, "[v]ersions: string",
-                "software versions");
-  cmd.addSubGroup("3d model measurement units:");
-  cmd.addOption("--measurement-units", "+mu", 3, "[CSD] [CV] [CM]: string (default: UCUM, um, um)",
-                "measurement units defined by coding scheme\ndesignator CSD, code value CV, code meaning CM");
-  addOutputOptions(cmd);
-}
 
-void DcmEncapsulatedDocument::addGeneralOptions(OFCommandLine &cmd)
+static void addDocumentOptions(OFCommandLine &cmd)
 {
-  cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
-  cmd.addOption("--help", "-h", "print this help text and exit", OFCommandLine::AF_Exclusive);
-  cmd.addOption("--version", "print version information and exit", OFCommandLine::AF_Exclusive);
-  OFLog::addOptions(cmd);
+    cmd.addGroup("DICOM document options:");
+
+    cmd.addSubGroup("document title:");
+    cmd.addOption("--title",               "+t", 1, "[t]itle: string (default: empty)", "document title");
+    cmd.addOption("--concept-name",        "+cn", 3, "[CSD] [CV] [CM]: string (default: empty)",
+                    "coded representation of document title defined\nby coding scheme designator CSD,\n"
+                    "code value CV and code meaning CM");
+    cmd.addSubGroup("patient data:");
+    cmd.addOption("--patient-name",        "+pn", 1, "[n]ame: string", "patient's name in DICOM PN syntax");
+    cmd.addOption("--patient-id",          "+pi", 1, "[i]d: string", "patient identifier");
+    cmd.addOption("--patient-birthdate",   "+pb", 1, "[d]ate: string (YYYYMMDD)", "patient's birth date");
+    cmd.addOption("--patient-sex",         "+ps", 1, "[s]ex: string (M, F or O)", "patient's sex");
+
+    cmd.addSubGroup("device data:");
+    cmd.addOption("--manufacturer",          "+mn", 1, "[n]ame: string", "manufacturer's name");
+    cmd.addOption("--manufacturer-model",    "+mm", 1, "[n]ame: string", "manufacturer's model name");
+    cmd.addOption("--device-serial",         "+ds", 1, "[n]umber: string", "device serial number");
+    cmd.addOption("--software-versions",     "+sv", 1, "[v]ersions: string", "software versions");
+
+    cmd.addSubGroup("manufacturing 3d model data (STL/MTL/OBJ only):");
+    cmd.addOption("--measurement-units",     "+mu", 3, "[CSD] [CV] [CM]: string (default: UCUM, um, um)",
+                  "measurement units defined by coding scheme\ndesignator CSD, code value CV, code meaning CM");
+
+    cmd.addSubGroup("study and series:");
+    cmd.addOption("--generate",            "+sg", "generate new study and\nseries UIDs (default)");
+    cmd.addOption("--study-from",          "+st", 1, "[f]ilename: string", "read patient/study data from DICOM file");
+    cmd.addOption("--series-from",         "+se", 1, "[f]ilename: string", "read patient/study/series data from DICOM file");
+
+    cmd.addSubGroup("instance number:");
+    cmd.addOption("--instance-one",        "+i1", "use instance number 1\n(default, not with +se)");
+    cmd.addOption("--instance-inc",        "+ii", "increment instance number (only with +se)");
+    cmd.addOption("--instance-set",        "+is", 1, "[i]nstance number: integer", "use instance number i");
+
+    cmd.addSubGroup("burned-in annotation:");
+    cmd.addOption("--annotation-yes",      "+an", "document contains patient identifying data\n(default)");
+    cmd.addOption("--annotation-no",       "-an", "document does not contain patient identif. data");
 }
 
-void DcmEncapsulatedDocument::addDocumentOptions(OFCommandLine &cmd)
+
+static void addOutputOptions(OFCommandLine &cmd)
 {
-  cmd.addGroup("DICOM document options:");
-  cmd.addSubGroup("document title:");
-  cmd.addOption("--title", "+t", 1, "[t]itle: string (default: empty)",
-                "document title");
-  cmd.addOption("--concept-name", "+cn", 3, "[CSD] [CV] [CM]: string (default: empty)",
-                "coded representation of document title defined\nby coding scheme designator CSD,\n"
-                "code value CV and code meaning CM");
-  cmd.addSubGroup("patient data:");
-  cmd.addOption("--patient-name", "+pn", 1, "[n]ame: string",
-                "patient's name in DICOM PN syntax");
-  cmd.addOption("--patient-id", "+pi", 1, "[i]d: string",
-                "patient identifier");
-  cmd.addOption("--patient-birthdate", "+pb", 1, "[d]ate: string (YYYYMMDD)",
-                "patient's birth date");
-  cmd.addOption("--patient-sex", "+ps", 1, "[s]ex: string (M, F or O)",
-                "patient's sex");
-  cmd.addSubGroup("study and series:");
-  cmd.addOption("--generate", "+sg", "generate new study and\nseries UIDs (default)");
-  cmd.addOption("--study-from", "+st", 1, "[f]ilename: string",
-                "read patient/study data from DICOM file");
-  cmd.addOption("--series-from", "+se", 1, "[f]ilename: string",
-                "read patient/study/series data from DICOM file");
-  cmd.addSubGroup("instance number:");
-  cmd.addOption("--instance-one", "+i1", "use instance number 1\n(default, not with +se)");
-  cmd.addOption("--instance-inc", "+ii", "increment instance number (only with +se)");
-  cmd.addOption("--instance-set", "+is", 1, "[i]nstance number: integer", "use instance number i");
-  cmd.addSubGroup("burned-in annotation:");
-  cmd.addOption("--annotation-yes", "+an", "document contains patient identifying data\n(default)");
-  cmd.addOption("--annotation-no", "-an", "document does not contain patient identif. data");
+    cmd.addGroup("processing options:");
+    cmd.addSubGroup("CDA processing options:");
+    cmd.addOption("--no-override",           "-ov", "CDA patient and document data must match study,\nseries or manually entered information (default)");
+    cmd.addOption("--override",              "+ov", "CDA's data will be overwritten by study, series\nor manually entered information");
+
+    cmd.addSubGroup("other processing options:");
+    cmd.addOption("--key",                 "-k", 1, "[k]ey: gggg,eeee=\"str\", path or dict. name=\"str\"", "add further attribute");
+
+    cmd.addGroup("output options:");
+
+    cmd.addSubGroup("output transfer syntax:");
+    cmd.addOption("--write-xfer-little",   "+te", "write with explicit VR little endian (default)");
+    cmd.addOption("--write-xfer-big",      "+tb", "write with explicit VR big endian TS");
+    cmd.addOption("--write-xfer-implicit", "+ti", "write with implicit VR little endian TS");
+
+    cmd.addSubGroup("group length encoding:");
+    cmd.addOption("--group-length-remove", "-g", "write without group length elements (default)");
+    cmd.addOption("--group-length-create", "+g", "write with group length elements");
+
+    cmd.addSubGroup("length encoding in sequences and items:");
+    cmd.addOption("--length-explicit",     "+e", "write with explicit lengths (default)");
+    cmd.addOption("--length-undefined",    "-e", "write with undefined lengths");
+
+    cmd.addSubGroup("data set trailing padding (not with --write-dataset):");
+    cmd.addOption("--padding-retain",      "-p=", "do not change padding (default)");
+    cmd.addOption("--padding-off",         "-p", "no padding (implicit if --write-dataset)");
+    cmd.addOption("--padding-create",      "+p", 2, "[f]ile-pad [i]tem-pad: integer",
+                  "align file on multiple of f bytes\nand items on multiple of i bytes");
 }
 
-void DcmEncapsulatedDocument::addOutputOptions(OFCommandLine &cmd)
+
+void DcmEncapsulatedDocument::addCommandlineOptions(OFCommandLine &cmd) const
 {
-  cmd.addGroup("processing options:");
-  cmd.addSubGroup("other processing options:");
-  cmd.addOption("--key", "-k", 1, "[k]ey: gggg,eeee=\"str\", path or dict. name=\"str\"",
-                "add further attribute");
-  cmd.addGroup("output options:");
-  cmd.addSubGroup("output transfer syntax:");
-  cmd.addOption("--write-xfer-little", "+te", "write with explicit VR little endian (default)");
-  cmd.addOption("--write-xfer-big", "+tb", "write with explicit VR big endian TS");
-  cmd.addOption("--write-xfer-implicit", "+ti", "write with implicit VR little endian TS");
-  cmd.addSubGroup("group length encoding:");
-  cmd.addOption("--group-length-recalc", "+g=", "recalculate group lengths if present (default)");
-  cmd.addOption("--group-length-create", "+g", "always write with group length elements");
-  cmd.addOption("--group-length-remove", "-g", "always write without group length elements");
-  cmd.addSubGroup("length encoding in sequences and items:");
-  cmd.addOption("--length-explicit", "+e", "write with explicit lengths (default)");
-  cmd.addOption("--length-undefined", "-e", "write with undefined lengths");
-  cmd.addSubGroup("data set trailing padding (not with --write-dataset):");
-  cmd.addOption("--padding-retain", "-p=", "do not change padding (default)");
-  cmd.addOption("--padding-off", "-p", "no padding (implicit if --write-dataset)");
-  cmd.addOption("--padding-create", "+p", 2, "[f]ile-pad [i]tem-pad: integer",
-                "align file on multiple of f bytes\nand items on multiple of i bytes");
+    cmd.setOptionColumns(LONGCOL, SHORTCOL);
+    cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
+    cmd.addParam("docfile-in",  "input filename to be converted");
+    cmd.addParam("dcmfile-out", "DICOM output filename (\"-\" for stdout)");
+
+    addGeneralOptions(cmd);
+
+    cmd.addGroup("input options:", LONGCOL, SHORTCOL + 2);
+    cmd.addSubGroup("input file format options:");
+    cmd.addOption("--filetype-auto",         "+fa", "automatically determine file type (default)");
+    cmd.addOption("--filetype-pdf",          "+fp", "expect PDF file");
+    cmd.addOption("--filetype-cda",          "+fc", "expect CDA file");
+    cmd.addOption("--filetype-stl",          "+fs", "expect STL file");
+    cmd.addOption("--filetype-mtl",          "+fm", "expect MTL file");
+    cmd.addOption("--filetype-obj",          "+fo", "expect OBJ file");
+
+    addDocumentOptions(cmd);
+
+    addOutputOptions(cmd);
 }
 
+
 void DcmEncapsulatedDocument::parseArguments(
         OFConsoleApplication &app,
         OFCommandLine &cmd)
 {
-  //command line parameters and options
-  cmd.getParam(1, opt_ifname);
-  cmd.getParam(2, opt_ofname);
-
-  OFLog::configureFromCommandLine(cmd, app);
-
-  dcmEnableGenerationOfNewVRs();
+    //command line parameters and options
+    cmd.getParam(1, ifname_);
+    cmd.getParam(2, ofname_);
 
-  // Override keys are applied at the very end of the conversion "pipeline"
-  OFList<OFString> overrideKeys;
+    // ---------- parse general options ----------
+    OFLog::configureFromCommandLine(cmd, app);
 
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--generate"))
-  {
-    opt_seriesFile = "";
-    opt_readSeriesInfo = OFFalse;
-  }
+    // ---------- parse input file format options ----------
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--filetype-auto")) ftype_ = DT_unknownDocument;
+    if (cmd.findOption("--filetype-pdf"))  ftype_ = DT_pdfDocument;
+    if (cmd.findOption("--filetype-cda"))  ftype_ = DT_cdaDocument;
+    if (cmd.findOption("--filetype-stl"))  ftype_ = DT_stlDocument;
+    if (cmd.findOption("--filetype-mtl"))  ftype_ = DT_mtlDocument;
+    if (cmd.findOption("--filetype-obj"))  ftype_ = DT_objDocument;
+    cmd.endOptionBlock();
 
-  if (cmd.findOption("--series-from"))
-  {
-    app.checkValue(cmd.getValue(opt_seriesFile));
-    opt_readSeriesInfo = OFTrue;
-  }
+    // ---------- parse document options ----------
 
-  if (cmd.findOption("--study-from"))
-  {
-    app.checkValue(cmd.getValue(opt_seriesFile));
-    opt_readSeriesInfo = OFFalse;
-  }
-  cmd.endOptionBlock();
-  if (cmd.findOption("--title"))
-  {
-    app.checkValue(cmd.getValue(opt_documentTitle));
-  }
-  if (cmd.findOption("--concept-name"))
-  {
-    app.checkValue(cmd.getValue(opt_conceptCSD));
-    app.checkValue(cmd.getValue(opt_conceptCV));
-    app.checkValue(cmd.getValue(opt_conceptCM));
-  }
-  if (cmd.findOption("--patient-name"))
-  {
-    app.checkValue(cmd.getValue(opt_patientName));
-    app.checkConflict("--patient-name", "--study-from or --series-from",
-                      opt_seriesFile != "");
-  }
-  if (cmd.findOption("--patient-id"))
-  {
-    app.checkValue(cmd.getValue(opt_patientID));
-    app.checkConflict("--patient-id", "--study-from or --series-from",
-                      opt_seriesFile != "");
-  }
-  if (cmd.findOption("--patient-birthdate"))
-  {
-    app.checkValue(cmd.getValue(opt_patientBirthdate));
-    app.checkConflict("--patient-birthdate", "--study-from or --series-from", opt_seriesFile != "");
-  }
-  if (cmd.findOption("--patient-sex"))
-  {
-    app.checkValue(cmd.getValue(opt_patientSex));
-    app.checkConflict("--patient-sex", "--study-from or --series-from", opt_seriesFile != "");
-  }
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--annotation-yes"))
-  {
-    opt_annotation = OFTrue;
-  }
-  if (cmd.findOption("--annotation-no"))
-  {
-    opt_annotation = OFFalse;
-  }
-  cmd.endOptionBlock();
-  if (ftype == "cda")
-  {
     cmd.beginOptionBlock();
-    if (cmd.findOption("--override"))
+    if (cmd.findOption("--generate"))
     {
-      opt_override = OFTrue;
+      seriesFile_ = "";
+      readSeriesInfo_ = OFFalse;
     }
-    if (cmd.findOption("--no-override"))
+
+    if (cmd.findOption("--series-from"))
     {
-      opt_override = OFFalse;
+      app.checkValue(cmd.getValue(seriesFile_));
+      readSeriesInfo_ = OFTrue;
+    }
+
+    if (cmd.findOption("--study-from"))
+    {
+      app.checkValue(cmd.getValue(seriesFile_));
+      readSeriesInfo_ = OFFalse;
     }
     cmd.endOptionBlock();
-  }
-  if (ftype == "stl")
-  {
-    if (cmd.findOption("--measurement-units"))
+
+    if (cmd.findOption("--title"))
     {
-      app.checkValue(cmd.getValue(opt_measurementUnitsCSD));
-      app.checkValue(cmd.getValue(opt_measurementUnitsCV));
-      app.checkValue(cmd.getValue(opt_measurementUnitsCM));
+      app.checkValue(cmd.getValue(documentTitle_));
+    }
+    if (cmd.findOption("--concept-name"))
+    {
+      app.checkValue(cmd.getValue(conceptCSD_));
+      app.checkValue(cmd.getValue(conceptCV_));
+      app.checkValue(cmd.getValue(conceptCM_));
+    }
+    if (cmd.findOption("--patient-name"))
+    {
+      app.checkValue(cmd.getValue(patientName_));
+      app.checkConflict("--patient-name", "--study-from or --series-from", seriesFile_.length() > 0);
+    }
+    if (cmd.findOption("--patient-id"))
+    {
+      app.checkValue(cmd.getValue(patientID_));
+      app.checkConflict("--patient-id", "--study-from or --series-from", seriesFile_.length() > 0);
+    }
+    if (cmd.findOption("--patient-birthdate"))
+    {
+      app.checkValue(cmd.getValue(patientBirthdate_));
+      app.checkConflict("--patient-birthdate", "--study-from or --series-from", seriesFile_.length() > 0);
+    }
+    if (cmd.findOption("--patient-sex"))
+    {
+      app.checkValue(cmd.getValue(patientSex_));
+      app.checkConflict("--patient-sex", "--study-from or --series-from", seriesFile_.length() > 0);
     }
-    if (cmd.findOption("--manufacturer")) app.checkValue(cmd.getValue(opt_manufacturer));
-    if (cmd.findOption("--manufacturer-model")) app.checkValue(cmd.getValue(opt_manufacturerModelName));
-    if (cmd.findOption("--device-serial")) app.checkValue(cmd.getValue(opt_deviceSerialNumber));
-    if (cmd.findOption("--software-versions")) app.checkValue(cmd.getValue(opt_softwareVersions));
-  }
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--write-xfer-little")) opt_oxfer = EXS_LittleEndianExplicit;
-  if (cmd.findOption("--write-xfer-big")) opt_oxfer = EXS_BigEndianExplicit;
-  if (cmd.findOption("--write-xfer-implicit")) opt_oxfer = EXS_LittleEndianImplicit;
-  cmd.endOptionBlock();
-
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--group-length-recalc")) opt_oglenc = EGL_recalcGL;
-  if (cmd.findOption("--group-length-create")) opt_oglenc = EGL_withGL;
-  if (cmd.findOption("--group-length-remove")) opt_oglenc = EGL_withoutGL;
-  cmd.endOptionBlock();
-
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--length-explicit")) opt_oenctype = EET_ExplicitLength;
-  if (cmd.findOption("--length-undefined")) opt_oenctype = EET_UndefinedLength;
-  cmd.endOptionBlock();
-
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--padding-retain"))
-  {
-    app.checkConflict("--padding-retain", "--write-dataset",
-                      opt_writeMode == EWM_dataset);
-    opt_opadenc = EPD_noChange;
-  }
-  if (cmd.findOption("--padding-off")) opt_opadenc = EPD_withoutPadding;
-  if (cmd.findOption("--padding-create"))
-  {
-    app.checkConflict("--padding-create", "--write-dataset",
-                      opt_writeMode == EWM_dataset);
-    app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0));
-    app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0));
-    opt_opadenc = EPD_withPadding;
-  }
-  cmd.endOptionBlock();
 
-  // create override attribute dataset (copied from findscu code)
-  if (cmd.findOption("--key", 0, OFCommandLine::FOM_FirstFromLeft))
-  {
-    const char *ovKey = NULL;
-    do
+    // initialize default for --series-from
+    if (seriesFile_.length() > 0 && readSeriesInfo_) increment_ = OFTrue;
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--instance-one"))
     {
-      app.checkValue(cmd.getValue(ovKey));
-      overrideKeys.push_back(ovKey);
-    } while (cmd.findOption("--key", 0, OFCommandLine::FOM_NextFromLeft));
-  }
-  DcmEncapsulatedDocument::setOverrideKeys(overrideKeys);
-  // initialize default for --series-from
-  if (opt_seriesFile != "" && opt_readSeriesInfo) opt_increment = OFTrue;
+      app.checkConflict("--instance-one", "--series-from", (seriesFile_.length() > 0) && readSeriesInfo_);
+      increment_ = OFFalse;
+      instance_ = 1;
+    }
+    if (cmd.findOption("--instance-inc"))
+    {
+      app.checkDependence("--instance-inc", "--series-from", (seriesFile_.length() > 0) && readSeriesInfo_);
+      increment_ = OFTrue;
+    }
+    if (cmd.findOption("--instance-set"))
+    {
+      increment_ = OFFalse;
+      app.checkValue(cmd.getValueAndCheckMin(instance_, 1));
+    }
+    cmd.endOptionBlock();
 
-  cmd.beginOptionBlock();
-  if (cmd.findOption("--instance-one"))
-  {
-    app.checkConflict("--instance-one", "--series-from",
-                      (opt_seriesFile != "") && opt_readSeriesInfo);
-    opt_increment = OFFalse;
-    opt_instance = 1;
-  }
-  if (cmd.findOption("--instance-inc"))
-  {
-    app.checkDependence("--instance-inc", "--series-from",
-                        (opt_seriesFile != "") && opt_readSeriesInfo);
-    opt_increment = OFTrue;
-  }
-  if (cmd.findOption("--instance-set"))
-  {
-    opt_increment = OFFalse;
-    app.checkValue(cmd.getValueAndCheckMin(opt_instance, 1));
-  }
-  cmd.endOptionBlock();
-}
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--annotation-yes"))
+    {
+      annotation_ = OFTrue;
+    }
+    if (cmd.findOption("--annotation-no"))
+    {
+      annotation_ = OFFalse;
+    }
+    cmd.endOptionBlock();
 
-OFCondition DcmEncapsulatedDocument::createIdentifiers(OFLogger &appLogger)
-{
-  char buf[100];
-  OFCondition cond = EC_Normal;
-  Sint32 incrementedInstance = 0;
-  if (opt_seriesFile != "")
-  {
-    DcmFileFormat dfile;
-    cond = dfile.loadFile(opt_seriesFile, EXS_Unknown, EGL_noChange);
-    if (cond.bad())
+    // ---------- parse CDA processing options ----------
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--override"))
     {
-      OFLOG_WARN(appLogger, cond.text()
-              << ": reading file: " << opt_seriesFile);
+      app.checkConflict("--override", "--filetype-pdf", ftype_ == DT_pdfDocument);
+      app.checkConflict("--override", "--filetype-stl", ftype_ == DT_stlDocument);
+      app.checkConflict("--override", "--filetype-stl", ftype_ == DT_mtlDocument);
+      app.checkConflict("--override", "--filetype-stl", ftype_ == DT_objDocument);
+      override_ = OFTrue;
     }
-    else
+    if (cmd.findOption("--no-override"))
     {
-      const char *c = NULL;
+      app.checkConflict("--no-override", "--filetype-pdf", ftype_ == DT_pdfDocument);
+      app.checkConflict("--no-override", "--filetype-stl", ftype_ == DT_stlDocument);
+      app.checkConflict("--no-override", "--filetype-stl", ftype_ == DT_mtlDocument);
+      app.checkConflict("--no-override", "--filetype-stl", ftype_ == DT_objDocument);
+      override_ = OFFalse;
+    }
+    cmd.endOptionBlock();
+
+    // ---------- parse device data options ----------
+
+    if (cmd.findOption("--manufacturer"))
+    {
+        app.checkValue(cmd.getValue(manufacturer_));
+    }
+    if (cmd.findOption("--manufacturer-model"))
+    {
+        app.checkValue(cmd.getValue(manufacturerModelName_));
+    }
+    if (cmd.findOption("--device-serial"))
+    {
+        app.checkValue(cmd.getValue(deviceSerialNumber_));
+    }
+    if (cmd.findOption("--software-versions"))
+    {
+        app.checkValue(cmd.getValue(softwareVersions_));
+    }
+
+    // ---------- parse STL processing options ----------
+
+    if (cmd.findOption("--measurement-units"))
+    {
+        app.checkConflict("--measurement-units", "--filetype-cda", ftype_ == DT_cdaDocument);
+        app.checkConflict("--measurement-units", "--filetype-pdf", ftype_ == DT_pdfDocument);
+        app.checkValue(cmd.getValue(measurementUnitsCSD_));
+        app.checkValue(cmd.getValue(measurementUnitsCV_));
+        app.checkValue(cmd.getValue(measurementUnitsCM_));
+    }
+
+    // ---------- parse input file format options ----------
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--write-xfer-little")) oxfer_ = EXS_LittleEndianExplicit;
+    if (cmd.findOption("--write-xfer-big")) oxfer_ = EXS_BigEndianExplicit;
+    if (cmd.findOption("--write-xfer-implicit")) oxfer_ = EXS_LittleEndianImplicit;
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--group-length-remove")) oglenc_ = EGL_withoutGL;
+    if (cmd.findOption("--group-length-create")) oglenc_ = EGL_withGL;
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--length-explicit")) oenctype_ = EET_ExplicitLength;
+    if (cmd.findOption("--length-undefined")) oenctype_ = EET_UndefinedLength;
+    cmd.endOptionBlock();
+
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--padding-retain"))
+    {
+      app.checkConflict("--padding-retain", "--write-dataset",
+                        writeMode_ == EWM_dataset);
+      opadenc_ = EPD_noChange;
+    }
+    if (cmd.findOption("--padding-off")) opadenc_ = EPD_withoutPadding;
+    if (cmd.findOption("--padding-create"))
+    {
+      app.checkConflict("--padding-create", "--write-dataset",
+                        writeMode_ == EWM_dataset);
+      app.checkValue(cmd.getValueAndCheckMin(filepad_, 0));
+      app.checkValue(cmd.getValueAndCheckMin(itempad_, 0));
+      opadenc_ = EPD_withPadding;
+    }
+    cmd.endOptionBlock();
+
+    // create override attribute dataset
+    overrideKeys_.clear();
+    if (cmd.findOption("--key", 0, OFCommandLine::FOM_FirstFromLeft))
+    {
+      const char *ovKey = NULL;
+      do
+      {
+        app.checkValue(cmd.getValue(ovKey));
+        overrideKeys_.push_back(ovKey);
+      } while (cmd.findOption("--key", 0, OFCommandLine::FOM_NextFromLeft));
+    }
+
+}
+
+
+OFCondition DcmEncapsulatedDocument::createIdentifiers()
+{
+  char buf[100];
+  OFCondition cond = EC_Normal;
+  Sint32 incrementedInstance = 0;
+  if (seriesFile_.length() > 0)
+  {
+    DCMDATA_DEBUG("Reading series file");
+    DcmFileFormat dfile;
+    cond = dfile.loadFile(seriesFile_, EXS_Unknown, EGL_noChange);
+
+    if (cond.good())
+    {
+      const char *c = NULL;
       DcmDataset *dset = dfile.getDataset();
       if (dset)
       {
-        OFLOG_TRACE(appLogger, "reading patient attributes");
+        DCMDATA_TRACE("reading patient attributes");
         c = NULL;
         if (dset->findAndGetString(DCM_PatientName, c).good() && c)
         {
-          opt_patientName = c;
+          patientName_ = c;
         }
         c = NULL;
         if (dset->findAndGetString(DCM_PatientID, c).good() && c)
         {
-          opt_patientID = c;
+          patientID_ = c;
         }
         c = NULL;
         if (dset->findAndGetString(DCM_PatientBirthDate, c).good() && c)
         {
-          opt_patientBirthdate = c;
+          patientBirthdate_ = c;
         }
         c = NULL;
         if (dset->findAndGetString(DCM_PatientSex, c).good() && c)
         {
-          opt_patientSex = c;
+          patientSex_ = c;
         }
-        OFLOG_TRACE(appLogger, "reading study attributes");
+        DCMDATA_TRACE("reading study attributes");
         c = NULL;
         if (dset->findAndGetString(DCM_StudyInstanceUID, c).good() && c)
         {
-          opt_studyUID = c;
+          studyUID_ = c;
+        }
+        c = NULL;
+        if (dset->findAndGetString(DCM_SpecificCharacterSet, c).good() && c)
+        {
+          specificCharSet_ = c;
         }
-        OFLOG_TRACE(appLogger, "reading series attributes");
-        if (opt_readSeriesInfo)
+        DCMDATA_TRACE("reading series attributes");
+        if (readSeriesInfo_)
         {
           c = NULL;
           if (dset->findAndGetString(DCM_SeriesInstanceUID, c).good() && c)
           {
-            opt_seriesUID = c;
+            seriesUID_ = c;
+          }
+          c = NULL;
+          if (dset->findAndGetString(DCM_Modality, c).good() && c)
+          {
+            modality_ = c;
           }
           if (dset->findAndGetSint32(DCM_InstanceNumber,
                                      incrementedInstance).good())
@@ -854,627 +818,807 @@ OFCondition DcmEncapsulatedDocument::createIdentifiers(OFLogger &appLogger)
           {
             incrementedInstance = 0;
           }
-          if (opt_increment) opt_instance = incrementedInstance;
+          if (increment_) instance_ = incrementedInstance;
+        }
+
+        DCMDATA_TRACE("reading reading device attributes");
+        c = NULL;
+        if (dset->findAndGetString(DCM_Manufacturer, c).good() && c)
+        {
+          manufacturer_ = c;
+        }
+        c = NULL;
+        if (dset->findAndGetString(DCM_ManufacturerModelName, c).good() && c)
+        {
+          manufacturerModelName_ = c;
+        }
+        c = NULL;
+        if (dset->findAndGetString(DCM_DeviceSerialNumber, c).good() && c)
+        {
+          deviceSerialNumber_ = c;
+        }
+        c = NULL;
+        if (dset->findAndGetString(DCM_SoftwareVersions, c).good() && c)
+        {
+          softwareVersions_ = c;
         }
-        if (ftype == "stl")
+
+        if (ftype_ == DT_stlDocument || ftype_ == DT_mtlDocument || ftype_ == DT_objDocument)
         {
-          OFLOG_TRACE(appLogger, "reading STL specific information");
+          DCMDATA_TRACE("reading STL/MTL/OBJ specific information");
           c = NULL;
-          OFLOG_TRACE(appLogger, "reading Frame of Reference Info");
           if (dset->findAndGetString(DCM_FrameOfReferenceUID, c).good() && c)
           {
-            opt_frameOfReferenceUID = c;
+            frameOfReferenceUID_ = c;
           }
           c = NULL;
           if (dset->findAndGetString(DCM_PositionReferenceIndicator, c).good() && c)
           {
-            opt_positionReferenceIndicator = c;
-          }
-          OFLOG_TRACE(appLogger, "reading Enhanced Equipment info");
-          c = NULL;
-          if (dset->findAndGetString(DCM_Manufacturer, c).good() && c)
-          {
-            opt_manufacturer = c;
-          }
-          c = NULL;
-          if (dset->findAndGetString(DCM_ManufacturerModelName, c).good() && c)
-          {
-            opt_manufacturerModelName = c;
-          }
-          c = NULL;
-          if (dset->findAndGetString(DCM_DeviceSerialNumber, c).good() && c)
-          {
-            opt_deviceSerialNumber = c;
+            positionReferenceIndicator_ = c;
           }
-          c = NULL;
-          if (dset->findAndGetString(DCM_SoftwareVersions, c).good() && c)
-          {
-            opt_softwareVersions = c;
-          }
-          OFLOG_TRACE(appLogger, "reading manufacturing 3d model info");
-          {
 
-            OFLOG_TRACE(appLogger, "manufacturing 3d model info read successfully");
-          }
         }
       }
     }
+    else
+    {
+        DCMDATA_ERROR("Error reading series file '" << seriesFile_ << "': " << cond.text());
+        return cond;
+    }
   }
-  if (opt_studyUID.empty())
+
+  if (studyUID_.empty())
   {
     dcmGenerateUniqueIdentifier(buf, SITE_STUDY_UID_ROOT);
-    opt_studyUID = buf;
+    studyUID_ = buf;
   }
-  if (opt_seriesUID.empty())
+  if (seriesUID_.empty())
   {
     dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
-    opt_seriesUID = buf;
+    seriesUID_ = buf;
   }
+
   return cond;
 }
 
-int DcmEncapsulatedDocument::insertEncapsulatedDocument(
-        DcmItem *dataset,
-        OFLogger &appLogger)
+
+OFCondition DcmEncapsulatedDocument::formatSpecificProcessing()
 {
-  char buf[100];
-  size_t fileSize = 0;
-  size_t buflen = 100;
-  struct stat fileStat;
+    if (ftype_ == DT_cdaDocument)
+    {
+        // so far we only have format specific processing code for CDA
+        return getCDAData();
+    }
+    return EC_Normal;
+}
 
-  if (0 == stat(opt_ifname.c_str(), &fileStat))
-  {
-    fileSize = OFstatic_cast(size_t, fileStat.st_size);
-  }
-  else
-  {
-    OFLOG_ERROR(appLogger, "file " << opt_ifname << " not found");
-    return EXITCODE_NO_INPUT_FILES;
-  }
-  if (fileSize == 0)
-  {
-    OFLOG_ERROR(appLogger, "file " << opt_ifname << " is empty");
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  FILE *encapfile = fopen(opt_ifname.c_str(), "rb");
-  if (encapfile == NULL)
-  {
-    OFLOG_ERROR(appLogger, "unable to read file " << opt_ifname);
-    return EXITCODE_CANNOT_READ_INPUT_FILE;
-  }
-  if (fileSize < buflen)
-  {
-    buflen = fileSize;
-  }
-  if (buflen != fread(buf, 1, buflen, encapfile))
-  {
-    OFLOG_ERROR(appLogger, "read error in file " << opt_ifname);
-    fclose(encapfile);
-    return EXITCODE_INVALID_INPUT_FILE;
-  }
-  if (ftype == "pdf")
-  {
-    // check magic word for PDF file
-    if (0 != strncmp("%PDF-", buf, 5))
+static size_t skipWhitespaceAndCommentLines(const char *buf, size_t buflen)
+{
+    size_t i=0;
+    while (OFTrue)
     {
-      OFLOG_ERROR(appLogger, "file " << opt_ifname << " is not a PDF file");
-      fclose(encapfile);
-      return EXITCODE_INVALID_INPUT_FILE;
+        // skip whitespace at beginning of line
+        while (i < buflen && (buf[i]==' ' || buf[i]=='\t')) ++i;
+
+        // skip comment line
+        if ((i < buflen) && (buf[i] == '#'))
+        {
+          // skip to the end of the comment line
+          while (i < buflen && (buf[i] != '\r' && buf[i] != '\n')) ++i;
+        }
+        else if (i < buflen && (buf[i]=='\r' || buf[i]=='\n'))
+        {
+            // skip empty line
+            ++i;
+        }
+        else return i; // end of buffer or keyword found
     }
-    // check PDF version number
-    char *version = buf + 5;
-    OFBool found = OFFalse;
-    for (int i = 0; i < 5; ++i)
+}
+
+static OFString getNextKeyword(const char *buf)
+{
+    size_t i=0;
+    char c = buf[i];
+    while ((c != ' ') && (c != '\t') && (c != '\0') && (c != '\r') && (c != '\n'))
     {
-      if (version[i] == 10 || version[i] == 13)
-      {
-        version[i] = 0; // insert end of string
-        found = OFTrue;
-        break;
-      }
+      ++i;
+      c = buf[i];
+    }
+    return OFString(buf, i);
+}
+
+static const char *objKeywords[] = {
+    "bevel", "bmat", "c_interp", "con", "cstype", "ctech", "curv", "curv2",
+    "d_interp", "deg", "end", "f", "g", "hole", "l", "lod", "mg", "mtllib",
+    "o", "p", "parm", "s", "scrv", "shadow_obj", "sp", "stech", "step",
+    "surf", "trace_obj", "trim", "usemtl", "v", "vn", "vp", "vt"
+};
+
+
+OFCondition DcmEncapsulatedDocument::insertEncapsulatedDocument()
+{
+#define INSERTBUFFERLENGTH 4096
+    char buf[INSERTBUFFERLENGTH+1];
+    size_t fileSize = 0;
+    size_t buflen = INSERTBUFFERLENGTH;
+    struct stat fileStat;
+    DcmDataset *dataset = dfile_.getDataset();
+
+    // determine length of document file
+    if (0 == stat(ifname_.c_str(), &fileStat))
+    {
+      fileSize = OFstatic_cast(size_t, fileStat.st_size);
+    }
+    else
+    {
+      DCMDATA_ERROR("file " << ifname_ << " not found");
+      return EC_InvalidStream;
+    }
+    if (fileSize == 0)
+    {
+      DCMDATA_ERROR("file " << ifname_ << " is empty");
+      return EC_InvalidStream;
+    }
+
+    // read the first 4096 bytes (or the full document if shorter)
+    FILE *encapfile = fopen(ifname_.c_str(), "rb");
+    if (encapfile == NULL)
+    {
+      DCMDATA_ERROR("unable to read file " << ifname_);
+      return EC_InvalidStream;
     }
-    if (!found)
+    if (fileSize < buflen)
     {
-      OFLOG_ERROR(appLogger, "file " << opt_ifname
-              << ": unable to decode PDF version number");
+      buflen = fileSize;
+    }
+    if (buflen != fread(buf, 1, buflen, encapfile))
+    {
+      DCMDATA_ERROR("read error in file " << ifname_);
       fclose(encapfile);
-      return EXITCODE_INVALID_INPUT_FILE;
+      return EC_InvalidStream;
     }
-    OFLOG_INFO(appLogger, "file " << opt_ifname
-            << ": PDF " << version << ", "
-            << (fileSize + 1023) / 1024 << "kB");
-  }
-  else
-  {
-    if (ftype == "cda")
+
+    // null terminate buffer
+    buf[buflen] = '\0';
+
+    // if the user has not specified the file type, determine it from the file content
+
+    // check for PDF document type
+    if (ftype_ == DT_unknownDocument)
     {
-      //xml validation occurs when getting data
-      OFLOG_INFO(appLogger, "file " << opt_ifname
-              << ": HL7 CDA file (XML Format)" << ", "
-              << (fileSize + 1023) / 1024 << "kB");
+        // If the document starts with "%PDF-", it is a PDF document
+        if ((buflen > 5) && (0 == strncmp("%PDF-", buf, 5))) ftype_ = DT_pdfDocument;
     }
-    else
+
+    // check for CDA document type
+    if (ftype_ == DT_unknownDocument)
     {
-      if (ftype == "stl")
-      {
-        // Each facet contains:
-        //  - Normals: 3 floats (4 bytes)
-        //  - Vertices: 3x floats (4 byte each, 12 bytes total)
-        //  - AttributeCount: 1 short (2 bytes)
-        // Total: 50 bytes per facet
-        const size_t facetSize32 = 3 * sizeof(Float32)
-                                   + 3 * 3 * sizeof(Float32)
-                                   + sizeof(Uint16);
-        const size_t facetSize64 = 3 * sizeof(Float64)
-                                   + 3 * 3 * sizeof(Float64)
-                                   + sizeof(Uint16);
-        // STL validation for ASCII CODE
-        if (fileSize < 15)
+        size_t i = 0;
+        // in a CDA document, the first non-whitespace character is "<"
+        while (i < buflen && OFStandard::isspace(buf[i])) ++i;
+        // we also check for the presence of the keyword "ClinicalDocument"
+        if ((i < buflen && buf[i] == '<') && (NULL != strstr(buf, "ClinicalDocument"))) ftype_ = DT_cdaDocument;
+    }
+
+    // check for binary STL document type
+    if (ftype_ == DT_unknownDocument)
+    {
+        // See comments in the STL section below for explanation of the identification algorithm
+        if (fileSize >= 84)
         {
-          // "solid " and "endsolid " markers for an ASCII file
-          OFLOG_ERROR(appLogger, "The STL file is not long enough"
-                  << " (" << fileSize << "kB)");
-          fclose(encapfile);
-          return EXITCODE_INVALID_INPUT_FILE;
+            const size_t facetSize32 = 12 * sizeof(Float32) + sizeof(Uint16);
+            const size_t facetSize64 = 12 * sizeof(Float64) + sizeof(Uint16);
+
+            // the number of triangles is stored as a 32-bit little endian integer at byte offset 80 in the file
+            Uint32 nTriangles = 0;
+            for (int j = 3; j >= 0; --j)
+            {
+                nTriangles = (nTriangles << 8) + OFstatic_cast(unsigned char, buf[80 + j]);
+            }
+            if (fileSize == (84 + nTriangles * facetSize32) || fileSize == (84 + nTriangles * facetSize64)) ftype_ = DT_stlDocument;
         }
-        // Binary files should never start with "solid ",
-        // but just in case, check for ASCII,
-        // and if not valid then check for binary...
-        // Look for text "solid " in first 6 bytes,
-        // indicating the possibility that this is an
-        // ASCII STL format.
-        if (0 == strncmp("solid ", buf, 6))
+    }
+
+    // check for MTL document type
+    if (ftype_ == DT_unknownDocument)
+    {
+        size_t i = skipWhitespaceAndCommentLines(buf, buflen);
+        if (i < buflen)
         {
-          OFLOG_ERROR(appLogger, "File " << opt_ifname
-                  << " starts with 'solid '. "
-                  << "It is a valid STL file but it is in ASCII Code"
-                  << "and DICOM only accepts binary STL");
-          return EXITCODE_INVALID_INPUT_FILE;
+          OFString keyword = getNextKeyword(buf+i);
+          if (keyword == "newmtl") ftype_ = DT_mtlDocument;
         }
-          //////STL validation for Binary Format
-        else
+    }
+
+    // check for OBJ document type
+    if (ftype_ == DT_unknownDocument)
+    {
+        size_t i = skipWhitespaceAndCommentLines(buf, buflen);
+        if (i < buflen)
         {
-          OFLOG_DEBUG(appLogger, "Magic word 'solid ' not found. "
-                  << "Validating STL file "
-                  << "in Binary format");
-          // 80-byte header + 4-byte "number of triangles" for a binary file
-          if (fileSize < 84)
+          OFString keyword = getNextKeyword(buf+i);
+          size_t numKeywords = sizeof(objKeywords)/sizeof(const char *);
+          for (size_t j=0; j < numKeywords; ++j)
           {
-            OFLOG_ERROR(appLogger, "The binary STL file is not long enough"
-                    << " (" << fileSize << "kB)");
-            fclose(encapfile);
-            return EXITCODE_INVALID_INPUT_FILE;
+              if (keyword == objKeywords[j])
+              {
+                  ftype_ = DT_objDocument;
+                  break;
+              }
           }
-          // Header is from bytes 0-79
-          // The number of Triangles starts at byte offset 80 and is a uint32 (4 Bytes)
-          char ntriangleschar[5];
-          for (int j = 0; j < 4; j++)
-            ntriangleschar[j] = buf[80 + j];
-          ntriangleschar[4] = 0;
-          Uint32 *nTriangles = OFreinterpret_cast(Uint32*, ntriangleschar);
-          // Verify that file size equals the sum of
-          // header + nTriangles value + all triangles
-          OFLOG_DEBUG(appLogger, "verifying if the file size is consistent");
-          if (fileSize == (84 + *OFconst_cast(Uint32*, nTriangles) * facetSize32) ||
-              fileSize == (84 + *OFconst_cast(Uint32*, nTriangles) * facetSize64))
-          {
-            OFLOG_DEBUG(appLogger, "File " << opt_ifname
-                    << " passed binary STL validation." << OFendl
-                    << "Assuming valid STL file "
-                    << "in binary format"
-            );
-            OFLOG_TRACE(appLogger, "The binary STL file is:" << OFendl
-                    << fileSize << " kB " << " as expected." << OFendl
-                    << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize32) << " kB for x86" << OFendl
-                    << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize64) << " kB for x64" << OFendl
-                    << "(84 + triangles number * facet size)" << OFendl
-                    << " number of Triangles " << *OFconst_cast(Uint32 * , nTriangles) << OFendl
-                    << " nTriangles (Uint32): " << nTriangles << OFendl
-                    << " facetSize32: " << facetSize32 << OFendl
-                    << " facetSize64: " << facetSize64 << OFendl
-            );
-          }
-          else
-          {
-            OFLOG_ERROR(appLogger, "The binary STL file is not consistent." << OFendl
-                    << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize32) << " kB for x86 and "
-                    << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize64) << " kB for x64 " << OFendl
-                    << "(84 + triangles number * facet size)" << OFendl
-                    << " number of Triangles " << *OFconst_cast(Uint32 * , nTriangles) << OFendl
-                    << " nTriangles (Uint32): " << nTriangles << OFendl
-                    << " facetSize32: " << facetSize32 << OFendl
-                    << " facetSize64: " << facetSize64 << OFendl
-            );
+        }
+    }
+
+    // check if we have determined the file type, bail out otherwise
+    if (ftype_ == DT_unknownDocument)
+    {
+        DCMDATA_ERROR("file " << ifname_ << " is of unknown file type");
+        fclose(encapfile);
+        return EC_InvalidStream;
+    }
+
+    OFBool found;
+    char *version;
+
+    // Each STL facet contains:
+    //  - Normals: 3 floats (4 bytes)
+    //  - Vertices: 3x floats (4 byte each, 12 bytes total)
+    //  - AttributeCount: 1 short (2 bytes)
+    // Total: 50 bytes per facet
+    const size_t facetSize32 = 12 * sizeof(Float32) + sizeof(Uint16);
+    const size_t facetSize64 = 12 * sizeof(Float64) + sizeof(Uint16);
+    size_t i;
+
+    switch (ftype_)
+    {
+        case DT_pdfDocument: // special handling for PDF documents
+            // check magic word for PDF file
+            if (0 != strncmp("%PDF-", buf, 5))
+            {
+              DCMDATA_ERROR("file " << ifname_ << " is not a PDF file");
+              fclose(encapfile);
+              return EC_InvalidStream;
+            }
+            // check PDF version number
+            version = buf + 5;
+            found = OFFalse;
+            for (i = 0; i < 5; ++i)
+            {
+              if (version[i] == 10 || version[i] == 13)
+              {
+                version[i] = 0; // insert end of string
+                found = OFTrue;
+                break;
+              }
+            }
+            if (!found)
+            {
+              DCMDATA_ERROR("file " << ifname_ << ": unable to decode PDF version number");
+              fclose(encapfile);
+              return EC_InvalidStream;
+            }
+            DCMDATA_INFO("file " << ifname_ << ": PDF " << version << ", " << (fileSize + 1023) / 1024 << "kB");
+            break;
+
+        case DT_cdaDocument: // special handling for CDA documents
+            // proper xml validation occurs later
+            DCMDATA_INFO("file " << ifname_ << ": HL7 CDA file (XML Format)" << ", " << (fileSize + 1023) / 1024 << "kB");
+            break;
+
+        case DT_stlDocument: // special handling for STL documents
+            // Check for an ASCII STL document (which is not permitted in DICOM)
+            if (fileSize < 15)
+            {
+              // "solid " and "endsolid " markers for an ASCII file
+              DCMDATA_ERROR("The STL file is not long enough" << " (" << fileSize << "kB)");
+              fclose(encapfile);
+              return EC_InvalidStream;
+            }
+
+            // Binary STL files should never start with "solid ", but just in case, check for ASCII,
+            // and if not valid then check for binary... Look for text "solid " in first 6 bytes,
+            // indicating the possibility that this is an ASCII STL format.
+            if (0 == strncmp("solid ", buf, 6))
+            {
+              DCMDATA_ERROR("File " << ifname_ << " starts with 'solid '. It is an STL file but it is in ASCII and DICOM only permits binary STL");
+              return EC_InvalidStream;
+            }
+            else
+            {
+              // STL validation for Binary Format
+              DCMDATA_DEBUG("Validating binary STL file");
+              // 80-byte header + 4-byte "number of triangles" for a binary file
+              if (fileSize < 84)
+              {
+                DCMDATA_ERROR("The binary STL file is not long enough" << " (" << fileSize << "kB)");
+                fclose(encapfile);
+                return EC_InvalidStream;
+              }
+              // Header is from bytes 0-79
+              // The number of Triangles starts at byte offset 80 and is a
+              // unsigned 32-bit integer in little endian byte order
+              Uint32 nTriangles = 0;
+              for (int j = 3; j >= 0; --j)
+                nTriangles = (nTriangles << 8) + OFstatic_cast(unsigned char, buf[80 + j]);
+
+              // Verify that file size equals the sum of
+              // header + nTriangles value + all triangles
+              DCMDATA_DEBUG("verifying if the file size is consistent");
+              if (fileSize == (84 + nTriangles * facetSize32) ||
+                  fileSize == (84 + nTriangles * facetSize64))
+              {
+                DCMDATA_INFO("file " << ifname_ << ": binary STL, " << nTriangles << " triangles");
+                DCMDATA_DEBUG("The binary STL file is "
+                        << fileSize << " bytes (expected "
+                        << (84 + nTriangles * facetSize32) << " bytes for x86 or "
+                        << (84 + nTriangles * facetSize64) << " bytes for x64), number of triangles: " << nTriangles);
+              }
+              else
+              {
+                DCMDATA_ERROR("The binary STL file is not consistent. Expected "
+                        << (84 + nTriangles * facetSize32) << " bytes for x86 or "
+                        << (84 + nTriangles * facetSize64) << " bytes for x64");
+                fclose(encapfile);
+                return EC_InvalidStream;
+              }
+            }
+            break;
+
+        case DT_mtlDocument: // special handling for MTL documents
+            i = skipWhitespaceAndCommentLines(buf, buflen);
+            if (i < buflen)
+            {
+                OFString keyword = getNextKeyword(buf+i);
+                if (keyword != "newmtl")
+                {
+                    DCMDATA_ERROR("Not a valid MTL file. Expected 'newmtl' as first keyword, but found '" << keyword << "'");
+                    fclose(encapfile);
+                    return EC_InvalidStream;
+                }
+            }
+            else
+            {
+                DCMDATA_ERROR("Not a valid MTL file. No keyword found");
+                fclose(encapfile);
+                return EC_InvalidStream;
+            }
+            DCMDATA_INFO("file " << ifname_ << ": Wavefront MTL");
+            break;
+
+        case DT_objDocument: // special handling for OBJ documents
+            i = skipWhitespaceAndCommentLines(buf, buflen);
+            if (i < buflen)
+            {
+                OFString keyword = getNextKeyword(buf+i);
+                size_t numKeywords = sizeof(objKeywords)/sizeof(const char *);
+                found = OFFalse;
+                for (size_t j=0; j < numKeywords; ++j)
+                {
+                    if (keyword == objKeywords[j])
+                    {
+                        found = OFTrue;
+                        break;
+                    }
+                }
+                if (!found)
+                {
+                    DCMDATA_ERROR("Not a valid OBJ file. Unsupported keyword '" << keyword << "' found");
+                    fclose(encapfile);
+                    return EC_InvalidStream;
+                }
+            }
+            else
+            {
+                DCMDATA_ERROR("Not a valid OBJ file. No keyword found");
+                fclose(encapfile);
+                return EC_InvalidStream;
+            }
+            DCMDATA_INFO("file " << ifname_ << ": Wavefront OBJ");
+            break;
+
+        case DT_unknownDocument:
+            DCMDATA_ERROR("Unsupported filetype. This should not happen.");
             fclose(encapfile);
-            return EXITCODE_INVALID_INPUT_FILE;
-          }
+            return EC_InvalidStream;
+            break;
+    }
+
+    // seek to start of file
+    if (0 != fseek(encapfile, 0, SEEK_SET))
+    {
+      DCMDATA_ERROR("file " << ifname_ << ": seek error");
+      fclose(encapfile);
+      return EC_InvalidStream;
+    }
+
+    OFCondition result = EC_Normal;
+    DcmPolymorphOBOW *elem = new DcmPolymorphOBOW(DCM_EncapsulatedDocument);
+    if (elem)
+    {
+      size_t numBytes = fileSize;
+
+      // Store Encapsulated Document Length, according to CP 1851
+      result = dataset->putAndInsertUint32(DCM_EncapsulatedDocumentLength, OFstatic_cast(Uint32, numBytes));
+
+      // allocate an even number of bytes
+      if (numBytes & 1) ++numBytes;
+      Uint8 *bytes = NULL;
+      if (result.good())
+      {
+        result = elem->createUint8Array(OFstatic_cast(Uint32, numBytes), bytes);
+      }
+      else
+      {
+        return result;
+      }
+
+      // read file content into Encapsulated Document attribute
+      if (result.good())
+      {
+        // blank pad byte
+        bytes[numBytes - 1] = 0;
+        // read file content
+        if (fileSize != fread(bytes, 1, fileSize, encapfile))
+        {
+          DCMDATA_ERROR("read error in file " << ifname_);
+          return result;
         }
       }
       else
       {
-        OFLOG_WARN(appLogger, "Filetype not supported or filetype not set. Current ftype is " << ftype << OFendl
-                << "The name of the passed logger is: " << appLogger.getName());
+        return EC_MemoryExhausted;
       }
     }
-  }
-  if (0 != fseek(encapfile, 0, SEEK_SET))
-  {
-    OFLOG_ERROR(appLogger, "file " << opt_ifname << ": seek error");
-    fclose(encapfile);
-    return EXITCODE_CANNOT_READ_INPUT_FILE;
-  }
-  OFCondition result = EC_Normal;
-  DcmPolymorphOBOW *elem = new DcmPolymorphOBOW(DCM_EncapsulatedDocument);
-  if (elem)
-  {
-    size_t numBytes = fileSize;
-    // according to CP 1851
-    result = dataset->putAndInsertUint32(DCM_EncapsulatedDocumentLength, OFstatic_cast(Uint32, numBytes));
-    if (numBytes & 1) ++numBytes;
-    Uint8 *bytes = NULL;
-    if (result.good())
-    {
-      result = elem->createUint8Array(OFstatic_cast(Uint32, numBytes), bytes);
-    }
     else
     {
-      return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
+      fclose(encapfile);
+      return EC_MemoryExhausted;
     }
+    // if successful, insert Encapsulated Document element into dataset
     if (result.good())
     {
-      // blank pad byte
-      bytes[numBytes - 1] = 0;
-      // read file content
-      if (fileSize != fread(bytes, 1, fileSize, encapfile))
-      {
-        OFLOG_ERROR(appLogger, "read error in file " << opt_ifname);
-        return EXITCODE_CANNOT_READ_INPUT_FILE;
-      }
+      result = dataset->insert(elem);
     }
     else
     {
-      return EXITCODE_MEMORY_EXHAUSTED;
+      delete elem;
+      DCMDATA_ERROR("Unsuccessful, did not insert element.");
+      return result;
     }
-  }
-  else
-  {
+
+    // close file end return
     fclose(encapfile);
-    return EXITCODE_MEMORY_EXHAUSTED;
-  }
-  // if successful, insert element into dataset
-  if (result.good())
-  {
-    result = dataset->insert(elem);
-  }
-  else
-  {
-    delete elem;
-    OFLOG_ERROR(appLogger, "Unsuccessful, did not insert element.");
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
-  // close file
-  fclose(encapfile);
-  if (result.good())
-  {
-    return EXITCODE_NO_ERROR;
-  }
-  else
-  {
-    return EXITCODE_CANNOT_WRITE_OUTPUT_FILE;
-  }
+    return result;
 }
 
-OFCondition DcmEncapsulatedDocument::createHeader(
-        DcmItem *dataset,
-        OFLogger &logger)
+OFCondition DcmEncapsulatedDocument::addFrameOfReferenceModule(DcmItem *dataset)
 {
-  OFCondition result = EC_Normal;
-  char buf[80];
-  // insert empty type 2 attributes
-  if (result.good()) result = dataset->insertEmptyElement(DCM_StudyDate);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_StudyTime);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_AccessionNumber);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_Manufacturer);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_ReferringPhysicianName);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_StudyID);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_ContentDate);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_ContentTime);
-  if (result.good()) result = dataset->insertEmptyElement(DCM_AcquisitionDateTime);
-  if (result.good())
-  {
-    if (opt_conceptCSD != "" && opt_conceptCV != "" && opt_conceptCM != "")
+    DCMDATA_TRACE("Validating Frame of Reference UID value");
+    char buf [100];
+    if (frameOfReferenceUID_.empty())
     {
-      result = DcmCodec::insertCodeSequence(dataset, DCM_ConceptNameCodeSequence,
-                                            opt_conceptCSD.c_str(),
-                                            opt_conceptCV.c_str(),
-                                            opt_conceptCM.c_str());
+        DCMDATA_DEBUG("Frame of Reference UID " << DCM_FrameOfReferenceUID << " value missing, generating a new one."
+        );
+        dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
+        frameOfReferenceUID_ = buf;
     }
     else
     {
-      result = dataset->insertEmptyElement(DCM_ConceptNameCodeSequence);
+        if (DcmUniqueIdentifier::checkStringValue(frameOfReferenceUID_, "1").bad())
+        {
+            DCMDATA_DEBUG("Frame of Reference UID " << DCM_FrameOfReferenceUID << " value was faulty, generating a new one."
+            );
+            dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
+            frameOfReferenceUID_ = buf;
+        }
     }
-  }
-  // insert const value attributes
-  if (result.good())
-  {
-    result = dataset->putAndInsertString(DCM_SpecificCharacterSet, "ISO_IR 100");
-  }
-  //insert encapsulated file storage UID (CDA/PDF/STL)
-  if (result.good())
-  {
-    if (ftype == "pdf")
+    DCMDATA_TRACE("Inserting Frame of Reference info to dataset");
+    OFCondition result = dataset->putAndInsertOFStringArray(DCM_FrameOfReferenceUID, frameOfReferenceUID_);
+
+    if (result.good())
+        result = dataset->putAndInsertOFStringArray(DCM_PositionReferenceIndicator, positionReferenceIndicator_);
+
+    return result;
+}
+
+
+OFCondition DcmEncapsulatedDocument::addEnhancedGeneralEquipmentModule(DcmItem *dataset)
+{
+    DCMDATA_TRACE("Validating and inserting Enhanced General Equipment fields");
+    if (manufacturer_.empty())
     {
-      OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset");
-      result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedPDFStorage);
+        manufacturer_ = "DCMTK_MANUFACTURING";
+        DCMDATA_INFO("No Manufacturer " << DCM_Manufacturer << " specified, will use dummy value.");
     }
-    if (ftype == "cda")
+    OFCondition result = dataset->putAndInsertOFStringArray(DCM_Manufacturer, manufacturer_);
+    if (result.good())
     {
-      OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset");
-      result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedCDAStorage);
-    }
-    if (ftype == "stl")
-    {//STL Specific modules
-      OFLOG_TRACE(logger, "Validating Frame of Reference UID value");
-      if (opt_frameOfReferenceUID.empty())
-      {
-        OFLOG_DEBUG(logger, "Frame of Reference UID "
-                << DCM_FrameOfReferenceUID
-                << " value was empty, generating a new one."
-        );
-        dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
-        opt_frameOfReferenceUID = buf;
-      }
-      else
-      {
-        if (DcmUniqueIdentifier::checkStringValue(opt_frameOfReferenceUID, "1").bad())
-        {
-          OFLOG_DEBUG(logger, "Frame of Reference UID "
-                  << DCM_FrameOfReferenceUID
-                  << " value was faulty, generating a new one."
-          );
-          dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT);
-          opt_frameOfReferenceUID = buf;
-        }
-      }
-      if (result.good())
-      {
-        OFLOG_TRACE(logger, "Inserting Frame of Reference info to dataset");
-        result = dataset->putAndInsertOFStringArray(DCM_FrameOfReferenceUID, opt_frameOfReferenceUID);
-      }
-      if (result.good())
-        result = dataset->putAndInsertOFStringArray(DCM_PositionReferenceIndicator, opt_positionReferenceIndicator);
-      OFLOG_TRACE(logger, "Validating and inserting Enhanced General Equipment fields");
-      if (result.good())
-      {
-        if (opt_manufacturer.empty())
+        if (manufacturerModelName_.empty())
         {
-          opt_manufacturer = "DCMTK_MANUFACTURING";
-          OFLOG_WARN(logger, "No Manufacturer "
-                  << DCM_Manufacturer
-                  << " provided nor found in series. This attribute is "
-                  << "required for Enhanced General Equipment module. "
-                  << opt_manufacturer
-                  << " will be inserted as dummy value."
-          );
+            manufacturerModelName_ = "DCMTK_3DMODEL";
+            DCMDATA_INFO("No Manufacturer Model Name " << DCM_ManufacturerModelName << " specified, will use dummy value.");
         }
-        result = dataset->putAndInsertOFStringArray(DCM_Manufacturer, opt_manufacturer);
-      }
-      if (result.good())
-      {
-        if (opt_manufacturerModelName.empty())
-        {
-          opt_manufacturerModelName = "DCMTK_3DMODEL_3";
-          OFLOG_WARN(logger, "No Manufacturer Model Name "
-                  << DCM_ManufacturerModelName
-                  << " provided nor found in series. This attribute is "
-                  << "required for Enhanced General Equipment module. "
-                  << opt_manufacturerModelName
-                  << " will be inserted as dummy value."
-          );
-        }
-        result = dataset->putAndInsertOFStringArray(DCM_ManufacturerModelName, opt_manufacturerModelName);
-      }
-      if (result.good())
-      {
-        if (opt_deviceSerialNumber.empty())
-        {
-          opt_deviceSerialNumber = "DCMTK01234567890";
-          OFLOG_WARN(logger, "No Device Serial Number "
-                  << DCM_DeviceSerialNumber
-                  << " provided nor found in series. This attribute is "
-                  << "required for Enhanced General Equipment module. "
-                  << opt_deviceSerialNumber
-                  << " will be inserted as dummy value."
-          );
-        }
-        result = dataset->putAndInsertOFStringArray(DCM_DeviceSerialNumber, opt_deviceSerialNumber);
-      }
-      if (result.good())
-      {
-        if (opt_softwareVersions.empty())
-        {
-          opt_softwareVersions = OFFIS_DCMTK_VERSION;
-          OFLOG_WARN(logger, "No Software Versions "
-                  << DCM_SoftwareVersions
-                  << " provided nor found in series. This attribute is "
-                  << "required for Enhanced General Equipment module. "
-                  << opt_softwareVersions
-                  << " will be inserted as dummy value."
-          );
-        }
-        result = dataset->putAndInsertOFStringArray(DCM_SoftwareVersions, opt_softwareVersions);
-      }
-      if (result.good())
-      {
-        if (opt_measurementUnitsCSD != "" && opt_measurementUnitsCV != "" && opt_measurementUnitsCM != "")
+        result = dataset->putAndInsertOFStringArray(DCM_ManufacturerModelName, manufacturerModelName_);
+    }
+    if (result.good())
+    {
+        if (deviceSerialNumber_.empty())
         {
-          result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence,
-                                                opt_measurementUnitsCSD.c_str(),
-                                                opt_measurementUnitsCV.c_str(),
-                                                opt_measurementUnitsCM.c_str());
+            deviceSerialNumber_ = "DCMTK_1234567890";
+            DCMDATA_INFO("No Device Serial Number " << DCM_DeviceSerialNumber << " specified, will use dummy value.");
         }
-        else
+        result = dataset->putAndInsertOFStringArray(DCM_DeviceSerialNumber, deviceSerialNumber_);
+    }
+    if (result.good())
+    {
+        if (softwareVersions_.empty())
         {
-          OFLOG_DEBUG(logger, "Measurement Units Code Sequence "
-                  << DCM_FrameOfReferenceUID
-                  << "had one or more empty values, generating default values."
-          );
-          result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence, "UCUM", "um", "um");
+            softwareVersions_ = OFFIS_DCMTK_VERSION;
+            DCMDATA_INFO("No Software Versions " << DCM_SoftwareVersions << " specified, will use dummy value.");
         }
-      }
-      if (result.good())
-      {
-        OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset");
-        result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedSTLStorage);
-      }
+        result = dataset->putAndInsertOFStringArray(DCM_SoftwareVersions, softwareVersions_);
     }
-  }
-  if (result.good())
-  {
-    if (ftype == "stl")
+    return result;
+}
+
+
+OFCondition DcmEncapsulatedDocument::addManufacturing3DModelModule(DcmItem *dataset)
+{
+    OFCondition result = EC_Normal;
+
+    if ((measurementUnitsCSD_.length() > 0) && (measurementUnitsCV_.length() > 0) && (measurementUnitsCM_.length() > 0))
     {
-      result = dataset->putAndInsertString(DCM_Modality, "M3D");
+      result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence,
+                                            measurementUnitsCSD_.c_str(),
+                                            measurementUnitsCV_.c_str(),
+                                            measurementUnitsCM_.c_str());
     }
     else
     {
-      // we are now using "DOC" for the modality, which seems to be more appropriate than "OT" (see CP-749)
-      result = dataset->putAndInsertString(DCM_Modality, "DOC");
+      DCMDATA_DEBUG("Measurement Units Code Sequence "
+              << DCM_MeasurementUnitsCodeSequence
+              << " had one or more empty values, generating default values."
+      );
+      result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence, "UCUM", "um", "um");
     }
-  }
-  if (result.good())
-  {
-    if (ftype != "stl")
+    return result;
+}
+
+
+OFCondition DcmEncapsulatedDocument::createHeader()
+{
+    OFCondition result = EC_Normal;
+    DcmDataset *dataset = dfile_.getDataset();
+
+    char buf[80];
+    // insert empty type 2 attributes
+    if (result.good()) result = dataset->insertEmptyElement(DCM_StudyDate);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_StudyTime);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_AccessionNumber);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_ReferringPhysicianName);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_StudyID);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_ContentDate);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_ContentTime);
+    if (result.good()) result = dataset->insertEmptyElement(DCM_AcquisitionDateTime);
+    if (result.good())
     {
-      OFLOG_TRACE(logger, "Inserting default Conversion type: Workstation (WSD) to dataset");
-      result = dataset->putAndInsertString(DCM_ConversionType, "WSD");
+      if ((conceptCSD_.length() > 0) && (conceptCV_.length() > 0) && (conceptCM_.length() > 0))
+      {
+          result = DcmCodec::insertCodeSequence(dataset, DCM_ConceptNameCodeSequence,
+                                                conceptCSD_.c_str(),
+                                                conceptCV_.c_str(),
+                                                conceptCM_.c_str());
+      }
+      else
+      {
+          result = dataset->insertEmptyElement(DCM_ConceptNameCodeSequence);
+      }
     }
-    else
+
+    // there is no way we could determine a meaningful series number, so we just use a constant.
+    if (result.good()) result = dataset->putAndInsertString(DCM_SeriesNumber, "1");
+
+    // insert variable value attributes
+    if (result.good()) result = dataset->putAndInsertString(DCM_DocumentTitle, documentTitle_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_PatientName, patientName_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_PatientID, patientID_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_PatientBirthDate, patientBirthdate_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_PatientSex, patientSex_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_BurnedInAnnotation, annotation_ ? "YES" : "NO");
+    OFStandard::snprintf(buf, sizeof(buf), "%ld", OFstatic_cast(long, instance_));
+    if (result.good()) result = dataset->putAndInsertString(DCM_InstanceNumber, buf);
+    dcmGenerateUniqueIdentifier(buf, SITE_INSTANCE_UID_ROOT);
+    if (result.good()) result = dataset->putAndInsertString(DCM_StudyInstanceUID, studyUID_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_SeriesInstanceUID, seriesUID_.c_str());
+    if (result.good()) result = dataset->putAndInsertString(DCM_SOPInstanceUID, buf);
+    // set instance creation date and time
+    OFString s;
+    if (result.good()) result = DcmDate::getCurrentDate(s);
+    if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, s);
+    if (result.good()) result = DcmTime::getCurrentTime(s);
+    if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, s);
+
+    // Device data. Special handling of these attributes for STL/MTL/OBJ,
+    // where they are type 1, will be provided later in addEnhancedGeneralEquipmentModule()
+    if (result.good() && (manufacturer_.length() > 0))
+        result = dataset->putAndInsertOFStringArray(DCM_Manufacturer, manufacturer_.c_str());
+        else result = dataset->insertEmptyElement(DCM_Manufacturer);
+    if (result.good() && (manufacturerModelName_.length() > 0)) result = dataset->putAndInsertOFStringArray(DCM_ManufacturerModelName, manufacturerModelName_.c_str());
+    if (result.good() && (deviceSerialNumber_.length() > 0)) result = dataset->putAndInsertOFStringArray(DCM_DeviceSerialNumber, deviceSerialNumber_.c_str());
+    if (result.good() && (softwareVersions_.length() > 0)) result = dataset->putAndInsertOFStringArray(DCM_SoftwareVersions, softwareVersions_.c_str());
+
+    //insert encapsulated file storage UID and additional attributes required per SOP class
+    if (result.good())
     {
-      OFLOG_TRACE(logger, "STL has no Conversion Type");
-      result = EC_Normal;
+        switch (ftype_)
+        {
+            case DT_pdfDocument:
+                DCMDATA_TRACE("Inserting SOPClassUID to dataset");
+                result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedPDFStorage);
+                if (result.good()) result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "application/pdf");
+                if (result.good())
+                {
+                    if ((modality_.length() > 0) && (modality_ != "DOC"))
+                    {
+                        DCMDATA_ERROR("Cannot use series information from '" << seriesFile_ << "': modality mismatch, expected 'DOC', found '" << modality_ << "'");
+                        result = EC_InvalidValue;
+                    }
+                    else result = dataset->putAndInsertString(DCM_Modality, "DOC");
+                }
+                if (result.good()) result = dataset->putAndInsertString(DCM_ConversionType, "WSD");
+                if (result.good() && (specificCharSet_.length() > 0)) result = dataset->putAndInsertString(DCM_SpecificCharacterSet, specificCharSet_.c_str());
+                break;
+
+            case DT_cdaDocument:
+                DCMDATA_TRACE("Inserting SOPClassUID to dataset");
+                result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedCDAStorage);
+                if (result.good()) result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "text/XML");
+                if (result.good())
+                {
+                    if ((modality_.length() > 0) && (modality_ != "DOC"))
+                    {
+                        DCMDATA_ERROR("Cannot use series information from '" << seriesFile_ << "': modality mismatch, expected 'DOC', found '" << modality_ << "'");
+                        result = EC_InvalidValue;
+                    }
+                    else result = dataset->putAndInsertString(DCM_Modality, "DOC");
+                }
+                if (result.good()) result = dataset->putAndInsertString(DCM_ConversionType, "WSD");
+                // Patient Name and Patient ID are guaranteed to be in UTF-8 (ISO_IR 192) in the CDA document
+                // and no other attributes from the series file are affected by character set issues
+                if ((! override_) || (specificCharSet_.length() == 0) ) specificCharSet_ = "ISO_IR 192";
+                if (result.good()) result = dataset->putAndInsertString(DCM_SpecificCharacterSet, specificCharSet_.c_str());
+                if (result.good() && cda_mediaTypes.length() > 0)
+                {
+                    result = dataset->putAndInsertString(DCM_ListOfMIMETypes, cda_mediaTypes.c_str());
+                }
+                if (result.good() && hl7_InstanceIdentifier.length() > 0)
+                {
+                    result = dataset->putAndInsertString(DCM_HL7InstanceIdentifier, hl7_InstanceIdentifier.c_str());
+                }
+                break;
+
+            case DT_stlDocument:
+                DCMDATA_TRACE("Inserting SOPClassUID to dataset");
+                result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedSTLStorage);
+                if (result.good()) result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "model/stl");
+                if (result.good())
+                {
+                    if ((modality_.length() > 0) && (modality_ != "M3D"))
+                    {
+                        DCMDATA_ERROR("Cannot use series information from '" << seriesFile_ << "': modality mismatch, expected 'M3D', found '" << modality_ << "'");
+                        result = EC_InvalidValue;
+                    }
+                    else result = dataset->putAndInsertString(DCM_Modality, "M3D");
+                }
+                if (result.good() && (specificCharSet_.length() > 0)) result = dataset->putAndInsertString(DCM_SpecificCharacterSet, specificCharSet_.c_str());
+                if (result.good()) result = addFrameOfReferenceModule(dataset);
+                if (result.good()) result = addEnhancedGeneralEquipmentModule(dataset);
+                if (result.good()) result = addManufacturing3DModelModule(dataset);
+                break;
+
+            case DT_mtlDocument:
+                DCMDATA_TRACE("Inserting SOPClassUID to dataset");
+                result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedMTLStorage);
+                if (result.good()) result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "model/mtl");
+                if (result.good())
+                {
+                    if ((modality_.length() > 0) && (modality_ != "M3D"))
+                    {
+                        DCMDATA_ERROR("Cannot use series information from '" << seriesFile_ << "': modality mismatch, expected 'M3D', found '" << modality_ << "'");
+                        result = EC_InvalidValue;
+                    }
+                    else result = dataset->putAndInsertString(DCM_Modality, "M3D");
+                }
+                if (result.good() && (specificCharSet_.length() > 0)) result = dataset->putAndInsertString(DCM_SpecificCharacterSet, specificCharSet_.c_str());
+                if (result.good()) result = addFrameOfReferenceModule(dataset);
+                if (result.good()) result = addEnhancedGeneralEquipmentModule(dataset);
+                if (result.good()) result = addManufacturing3DModelModule(dataset);
+                break;
+
+            case DT_objDocument:
+                DCMDATA_TRACE("Inserting SOPClassUID to dataset");
+                result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedOBJStorage);
+                if (result.good()) result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "model/obj");
+                if (result.good())
+                {
+                    if ((modality_.length() > 0) && (modality_ != "M3D"))
+                    {
+                        DCMDATA_ERROR("Cannot use series information from '" << seriesFile_ << "': modality mismatch, expected 'M3D', found '" << modality_ << "'");
+                        result = EC_InvalidValue;
+                    }
+                    else result = dataset->putAndInsertString(DCM_Modality, "M3D");
+                }
+                if (result.good() && (specificCharSet_.length() > 0)) result = dataset->putAndInsertString(DCM_SpecificCharacterSet, specificCharSet_.c_str());
+                if (result.good()) result = addFrameOfReferenceModule(dataset);
+                if (result.good()) result = addEnhancedGeneralEquipmentModule(dataset);
+                if (result.good()) result = addManufacturing3DModelModule(dataset);
+                break;
+
+            case DT_unknownDocument:
+                break;
+        }
     }
-  }
-  if (result.good())
-  {
-    // according to C.24.2.1 on part 3, (0042,0012) is text/XML for CDA.
-    if (ftype == "cda")
-      result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "text/XML");
-    // according to A.45.1.4.1 on part 3, MIME Type is application/pdf for PDF.
-    if (ftype == "pdf")
-      result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "application/pdf");
-    // according to A.85.1.4.2 on part 3, MIME Type is model/stl.
-    if (ftype == "stl")
-      result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "model/stl");
-  }
-  // there is no way we could determine a meaningful series number, so we just use a constant.
-  if (result.good()) result = dataset->putAndInsertString(DCM_SeriesNumber, "1");
-  // insert variable value attributes
-  if (result.good()) result = dataset->putAndInsertString(DCM_DocumentTitle, opt_documentTitle.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_PatientName, opt_patientName.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_PatientID, opt_patientID.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_PatientBirthDate, opt_patientBirthdate.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_PatientSex, opt_patientSex.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_BurnedInAnnotation, opt_annotation ? "YES" : "NO");
-  if (strlen(cda_mediaTypes.c_str()) > 0)
-  {
-    if (result.good()) result = dataset->putAndInsertString(DCM_ListOfMIMETypes, cda_mediaTypes.c_str());
-  }
-  if (hl7_InstanceIdentifier.size() > 0)
-  {
-    if (result.good()) result = dataset->putAndInsertString(DCM_HL7InstanceIdentifier, hl7_InstanceIdentifier.c_str());
-  }
-  OFStandard::snprintf(buf, sizeof(buf), "%ld", OFstatic_cast(long, opt_instance));
-  if (result.good()) result = dataset->putAndInsertString(DCM_InstanceNumber, buf);
-  dcmGenerateUniqueIdentifier(buf, SITE_INSTANCE_UID_ROOT);
-  if (result.good()) result = dataset->putAndInsertString(DCM_StudyInstanceUID, opt_studyUID.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_SeriesInstanceUID, opt_seriesUID.c_str());
-  if (result.good()) result = dataset->putAndInsertString(DCM_SOPInstanceUID, buf);
-  // set instance creation date and time
-  OFString s;
-  if (result.good()) result = DcmDate::getCurrentDate(s);
-  if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, s);
-  if (result.good()) result = DcmTime::getCurrentTime(s);
-  if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, s);
-  return result;
-}
 
-OFCondition DcmEncapsulatedDocument::applyOverrideKeys(DcmDataset *outputDset)
-{
-  // replace specific keys by those in overrideKeys, copied from findscu
-  OFListConstIterator(OFString) path = opt_overrideKeys.begin();
-  OFListConstIterator(OFString) endOfList = opt_overrideKeys.end();
-  OFCondition cond;
-  DcmPathProcessor proc;
-  while (path != endOfList)
-  {
-    cond = proc.applyPathWithValue(outputDset, *path);
-    if (cond.bad())
+    if (result.bad())
     {
-      OFString err;
-      err += "Bad override key/path: ";
-      err += *path;
-      err += ": ";
-      err += cond.text();
-      return makeOFCondition(OFM_dcmdata, 18, OF_error, err.c_str());
+        DCMDATA_ERROR("Error while creating DICOM header: " << result.text());
     }
-    path++;
-  }
-  return cond;
+    return result;
 }
 
-void DcmEncapsulatedDocument::setOverrideKeys(const OFList<OFString> &ovkeys)
-{
-  OFListConstIterator(OFString) it = ovkeys.begin();
-  OFListConstIterator(OFString) end = ovkeys.end();
-  while (it != end)
-  {
-    opt_overrideKeys.push_back(*it);
-    it++;
-  }
-}
 
-OFCondition DcmEncapsulatedDocument::saveFile(DcmFileFormat fileformat)
+OFCondition DcmEncapsulatedDocument::applyOverrideKeys()
 {
-  return fileformat.saveFile(opt_ofname, opt_oxfer, opt_oenctype, opt_oglenc,
-                             opt_opadenc, OFstatic_cast(Uint32, opt_filepad),
-                             OFstatic_cast(Uint32, opt_itempad));
-}
-
-OFString DcmEncapsulatedDocument::getInputFileName()
-{
-  return opt_ifname;
+    DcmDataset *outputDset = dfile_.getDataset();
+    // replace specific keys by those in overrideKeys, copied from findscu
+    OFListConstIterator(OFString) path = overrideKeys_.begin();
+    OFListConstIterator(OFString) endOfList = overrideKeys_.end();
+    OFCondition cond;
+    DcmPathProcessor proc;
+    if (path != endOfList)
+    {
+        DCMDATA_DEBUG("Applying override keys from command line");
+    }
+    while (path != endOfList)
+    {
+        cond = proc.applyPathWithValue(outputDset, *path);
+        if (cond.bad())
+        {
+          OFString err;
+          err += "Bad override key/path: ";
+          err += *path;
+          err += ": ";
+          err += cond.text();
+          DCMDATA_ERROR(err.c_str());
+          return makeOFCondition(OFM_dcmdata, 18, OF_error, err.c_str());
+        }
+        path++;
+    }
+    return cond;
 }
 
-void DcmEncapsulatedDocument::setInputFileName(OFString fName)
-{
-  opt_ifname = fName;
-}
 
-OFString DcmEncapsulatedDocument::getOutputFileName()
+OFCondition DcmEncapsulatedDocument::saveFile()
 {
-  return opt_ofname;
-}
+    OFCondition result = dfile_.saveFile(
+        ofname_, oxfer_, oenctype_, oglenc_, opadenc_,
+        OFstatic_cast(Uint32, filepad_), OFstatic_cast(Uint32, itempad_));
 
-void DcmEncapsulatedDocument::setOutputFileName(OFString fName)
-{
-  opt_ofname = fName;
+    if (result.bad())
+    {
+        DCMDATA_ERROR(result.text() << ": writing file: '" << ofname_ << "'");
+    }
+    return result;
 }
 
-OFString DcmEncapsulatedDocument::getFileType()
-{
-  return ftype;
-}
 
-void DcmEncapsulatedDocument::setFileType(OFString fType)
+OFString DcmEncapsulatedDocument::getInputFileName()
 {
-  ftype = fType;
+    return ifname_;
 }
 
-E_TransferSyntax DcmEncapsulatedDocument::getTransferSyntax()
-{
-  return opt_oxfer;
-}
 
-DcmEncapsulatedDocument::~DcmEncapsulatedDocument()
+OFString DcmEncapsulatedDocument::getOutputFileName()
 {
+    return ofname_;
 }
index 3dfbd8109eb1757966adc250e7cf7b901ff446a2..a27c93b5387dc8d682135446e6f4c190b051b5e7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2022, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -79,11 +79,18 @@ makeOFConditionConst(EC_PixelDataExplLengthIllegal,      OFM_dcmdata, 53, OF_err
 makeOFConditionConst(EC_ElemLengthExceeds32BitField,     OFM_dcmdata, 54, OF_error, "Length of element value exceeds maximum of 32-bit length field" );
 makeOFConditionConst(EC_CannotWriteJsonNumber,           OFM_dcmdata, 55, OF_error, "Cannot write 'nan' or 'inf' as JSON number" );
 makeOFConditionConst(EC_CannotWriteJsonInlineBinary,     OFM_dcmdata, 56, OF_error, "JSON InlineBinary encoding not supported for compressed pixel data" );
-makeOFConditionConst(EC_XMLParseError,                   OFM_dcmdata, 57, OF_error, "XML parse error" );
-makeOFConditionConst(EC_XMLValidationFailure,            OFM_dcmdata, 58, OF_error, "XML validation failure" );
-makeOFConditionConst(EC_SOPClassMismatch,                OFM_dcmdata, 59, OF_error, "SOP class mismatch" );
+makeOFConditionConst(EC_XMLParseError,                   OFM_dcmdata, 57, OF_error, "XML parse error"                            );
+makeOFConditionConst(EC_XMLValidationFailure,            OFM_dcmdata, 58, OF_error, "XML validation failure"                     );
+makeOFConditionConst(EC_SOPClassMismatch,                OFM_dcmdata, 59, OF_error, "SOP Class mismatch"                         );
 makeOFConditionConst(EC_UnknownUIDName,                  OFM_dcmdata, 60, OF_error, "Unknown UID name: No mapping to UID value defined" );
-makeOFConditionConst(EC_CannotWriteStringAsJsonNumber,   OFM_dcmdata, 61, OF_error, "Cannot write IS/DS string as JSON number" );
+makeOFConditionConst(EC_CannotWriteStringAsJSONNumber,   OFM_dcmdata, 61, OF_error, "Cannot write IS/DS string as JSON number"   );
+makeOFConditionConst(EC_CannotWriteBulkDataFile,         OFM_dcmdata, 62, OF_error, "Cannot write bulk data file"                );
+makeOFConditionConst(EC_CannotWriteJSONMultiframe,       OFM_dcmdata, 63, OF_error, "JSON encoding not supported for encapsulated multi-frame pixel data" );
+makeOFConditionConst(EC_InvalidJSONType,                 OFM_dcmdata, 64, OF_error, "Invalid JSON type"                          );
+makeOFConditionConst(EC_InvalidJSONContent,              OFM_dcmdata, 65, OF_error, "Invalid JSON content"                       );
+makeOFConditionConst(EC_BulkDataURINotSupported,         OFM_dcmdata, 66, OF_error, "BulkDataURI not yet supported"              );
+makeOFConditionConst(EC_UnsupportedURIType,              OFM_dcmdata, 67, OF_error, "Unsupported URI type"                       );
+makeOFConditionConst(EC_CommandLineFailed,               OFM_dcmdata, 68, OF_error, "Execution of command line failed"           );
 
 const unsigned short EC_CODE_CannotSelectCharacterSet     = 35;
 const unsigned short EC_CODE_CannotConvertCharacterSet    = 36;
index e8d6de688ed7522e26aebf4398c390394e549a92..b1a8c16c034eeef3a8b1e473f268444d91ceeeb9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -52,7 +52,9 @@
 
 DcmFileFormat::DcmFileFormat()
   : DcmSequenceOfItems(DCM_InternalUseTag),
-    FileReadMode(ERM_autoDetect)
+    FileReadMode(ERM_autoDetect),
+    ImplementationClassUID(OFFIS_IMPLEMENTATION_CLASS_UID),
+    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME)
 {
     DcmMetaInfo *MetaInfo = new DcmMetaInfo();
     DcmSequenceOfItems::itemList->insert(MetaInfo);
@@ -67,7 +69,9 @@ DcmFileFormat::DcmFileFormat()
 DcmFileFormat::DcmFileFormat(DcmDataset *dataset,
                              OFBool deepCopy)
   : DcmSequenceOfItems(DCM_InternalUseTag),
-    FileReadMode(ERM_autoDetect)
+    FileReadMode(ERM_autoDetect),
+    ImplementationClassUID(OFFIS_IMPLEMENTATION_CLASS_UID),
+    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME)
 {
     DcmMetaInfo *MetaInfo = new DcmMetaInfo();
     DcmSequenceOfItems::itemList->insert(MetaInfo);
@@ -93,7 +97,9 @@ DcmFileFormat::DcmFileFormat(DcmDataset *dataset,
 
 DcmFileFormat::DcmFileFormat(const DcmFileFormat &old)
   : DcmSequenceOfItems(old),
-    FileReadMode(old.FileReadMode)
+    FileReadMode(old.FileReadMode),
+    ImplementationClassUID(old.ImplementationClassUID),
+    ImplementationVersionName(old.ImplementationVersionName)
 {
 }
 
@@ -120,6 +126,8 @@ DcmFileFormat &DcmFileFormat::operator=(const DcmFileFormat &obj)
   {
     DcmSequenceOfItems::operator=(obj);
     FileReadMode = obj.FileReadMode;
+    ImplementationClassUID = obj.ImplementationClassUID;
+    ImplementationVersionName = obj.ImplementationVersionName;
   }
 
   return *this;
@@ -265,12 +273,13 @@ OFCondition DcmFileFormat::writeJson(STD_NAMESPACE ostream &out,
 // ********************************
 
 
-OFCondition DcmFileFormat::checkMetaHeaderValue(DcmMetaInfo *metainfo,
-                                                DcmDataset *dataset,
-                                                const DcmTagKey &atagkey,
-                                                DcmObject *obj,
-                                                const E_TransferSyntax oxfer,
-                                                const E_FileWriteMode writeMode)
+OFCondition DcmFileFormat::checkMetaHeaderValue(
+    DcmMetaInfo *metainfo,
+    DcmDataset *dataset,
+    const DcmTagKey &atagkey,
+    DcmObject *obj,
+    const E_TransferSyntax oxfer,
+    const E_FileWriteMode writeMode) const
     /*
      * This function checks if a particular data element of the file meta information header is
      * existent.  If the element is not existent, it will be inserted.  Additionally, this function
@@ -360,7 +369,7 @@ OFCondition DcmFileFormat::checkMetaHeaderValue(DcmMetaInfo *metainfo,
             }
             if (elem->ident() == EVR_UI)
             {
-                if ((writeMode == EWM_updateMeta) || (elem->getLength() == 0))
+                if ((writeMode == EWM_updateMeta) || (writeMode == EWM_createNewMeta) || (elem->getLength() == 0))
                 {
                     if (dataset->search(DCM_SOPClassUID, stack).good() && (stack.top()->ident() == EVR_UI))
                     {
@@ -402,7 +411,7 @@ OFCondition DcmFileFormat::checkMetaHeaderValue(DcmMetaInfo *metainfo,
             }
             if (elem->ident() == EVR_UI)
             {
-                if ((writeMode == EWM_updateMeta) || (elem->getLength() == 0))
+                if ((writeMode == EWM_updateMeta) || (writeMode == EWM_createNewMeta) || (elem->getLength() == 0))
                 {
                     if (dataset->search(DCM_SOPInstanceUID, stack).good() && (stack.top()->ident() == EVR_UI))
                     {
@@ -468,8 +477,7 @@ OFCondition DcmFileFormat::checkMetaHeaderValue(DcmMetaInfo *metainfo,
             }
             if (elem->ident() == EVR_UI)
             {
-                const char *uid = OFFIS_IMPLEMENTATION_CLASS_UID;
-                OFstatic_cast(DcmUniqueIdentifier *, elem)->putString(uid);
+                OFstatic_cast(DcmUniqueIdentifier *, elem)->putString(ImplementationClassUID.c_str());
             }
         }
         else if (tag == DCM_ImplementationVersionName)     // (0002,0013)
@@ -481,8 +489,7 @@ OFCondition DcmFileFormat::checkMetaHeaderValue(DcmMetaInfo *metainfo,
             }
             if (elem->ident() == EVR_SH)
             {
-                const char *uid = OFFIS_DTK_IMPLEMENTATION_VERSION_NAME;
-                OFstatic_cast(DcmShortString *, elem)->putString(uid);
+                OFstatic_cast(DcmShortString *, elem)->putString(ImplementationVersionName.c_str());
             }
         }
         else if ((tag == DCM_SourceApplicationEntityTitle) ||  // (0002,0016)
@@ -566,13 +573,27 @@ OFCondition DcmFileFormat::validateMetaInfo(const E_TransferSyntax oxfer,
         {
             DCMDATA_WARN("DcmFileFormat: Meta Information Header is not updated!");
         } else {
+            /* in the following, we want to make sure all elements of the meta header */
+            /* are existent in metinf and contain correct values */
+            DcmStack stack;
+
             /* start with empty file meta information */
             if (writeMode == EWM_createNewMeta)
+            {
+                /* search, and if present, store and remove the media storage SOP class and instance UID. */
+                metinf->search(DCM_MediaStorageSOPClassUID, stack, ESM_fromHere, OFFalse);
+                DcmElement *sopClassUID = metinf->remove(stack.top());
+                metinf->search(DCM_MediaStorageSOPInstanceUID, stack, ESM_fromHere, OFFalse);
+                DcmElement *sopInstanceUID = metinf->remove(stack.top());
+
+                /* clear the meta-header and the search stack */
                 metinf->clear();
+                stack.clear();
 
-            /* in the following, we want to make sure all elements of the meta header */
-            /* are existent in metinf and contain correct values */
-            DcmStack stack;
+                /* re-insert SOP class UID and SOP instance UID */
+                if (sopClassUID) metinf->insert(sopClassUID);
+                if (sopInstanceUID) metinf->insert(sopInstanceUID);
+            }
 
             /* DCM_FileMetaInformationGroupLength */
             metinf->search(DCM_FileMetaInformationGroupLength, stack, ESM_fromHere, OFFalse);
@@ -752,6 +773,11 @@ OFCondition DcmFileFormat::readUntilTag(DcmInputStream &inStream,
                     // remember the parent
                     dataset->setParent(this);
                 }
+
+                // initialize dataset transfer syntax members
+                // to make sure the values are correct even if the dataset is empty
+                dataset->initializeXfer(newxfer);
+
                 // check whether to read the dataset at all
                 if (FileReadMode != ERM_metaOnly)
                 {
@@ -817,6 +843,12 @@ OFCondition DcmFileFormat::write(DcmOutputStream &outStream,
      *                         in the file meta information header.
      */
 {
+    /* write as dataset (without meta header) */
+    if (writeMode == EWM_dataset)
+    {
+        return getDataset()->write(outStream, oxfer, enctype, wcache, glenc,
+            padenc, padlen, subPadlen, instanceLength);
+    }
     /* if the transfer state of this is not initialized, this is an illegal call */
     if (getTransferState() == ERW_notInitialized)
         errorFlag = EC_IllegalCall;
@@ -975,6 +1007,7 @@ OFCondition DcmFileFormat::saveFile(const OFFilename &fileName,
                                     const Uint32 subPadLength,
                                     const E_FileWriteMode writeMode)
 {
+    /* save as dataset (without meta header) */
     if (writeMode == EWM_dataset)
     {
         return getDataset()->saveFile(fileName, writeXfer, encodingType, groupLength,
@@ -1076,8 +1109,10 @@ DcmMetaInfo *DcmFileFormat::getMetaInfo()
 {
     errorFlag = EC_Normal;
     DcmMetaInfo *meta = NULL;
-    if (itemList->seek_to(0) != NULL && itemList->get()->ident() == EVR_metainfo)
-        meta = OFstatic_cast(DcmMetaInfo *, itemList->get());
+    // the meta information is the first item
+    DcmObject *object = itemList->seek(ELP_first);
+    if (object != NULL && object->ident() == EVR_metainfo)
+        meta = OFstatic_cast(DcmMetaInfo *, object);
     else
         errorFlag = EC_IllegalCall;
     return meta;
@@ -1091,8 +1126,10 @@ DcmDataset *DcmFileFormat::getDataset()
 {
     errorFlag = EC_Normal;
     DcmDataset *data = NULL;
-    if (itemList->seek_to(1) != NULL && itemList->get()->ident() == EVR_dataset)
-        data = OFstatic_cast(DcmDataset *, itemList->get());
+    // the dataset is the last item
+    DcmObject *object = itemList->seek(ELP_last);
+    if (object != NULL && object->ident() == EVR_dataset)
+        data = OFstatic_cast(DcmDataset *, object);
     else
         errorFlag = EC_IllegalCall;
     return data;
@@ -1106,7 +1143,9 @@ DcmDataset *DcmFileFormat::getAndRemoveDataset()
 {
     errorFlag = EC_Normal;
     DcmDataset *data = NULL;
-    if (itemList->seek_to(1) != NULL && itemList->get()->ident() == EVR_dataset)
+    // the dataset is the last item
+    DcmObject *object = itemList->seek(ELP_last);
+    if (object != NULL && object->ident() == EVR_dataset)
     {
         data = OFstatic_cast(DcmDataset *, itemList->remove());
         // forget about the parent
@@ -1165,3 +1204,18 @@ OFCondition DcmFileFormat::convertToUTF8()
     // the DICOM defined term "ISO_IR 192" is used for "UTF-8"
     return convertCharacterSet("ISO_IR 192", 0 /*flags*/);
 }
+
+void DcmFileFormat::setImplementationClassUID(const OFString& implementationClassUID)
+{
+    ImplementationClassUID = implementationClassUID;
+}
+
+void DcmFileFormat::setImplementationVersionName(const OFString& implementationVersionName)
+{
+    ImplementationVersionName = implementationVersionName;
+    if (ImplementationVersionName.length() > 16)
+    {
+        DCMDATA_WARN("DcmFileFormat: implementation version name too long");
+        ImplementationVersionName.erase(16);
+    }
+}
index daed3ce7ad491f230e05200570c8057b9a7d2b93..9c0181a4685c362ee528172ab318f924cd0ca7fe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,9 +26,7 @@
 #include "dcmtk/dcmdata/dcerror.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
index 28741a2e9c34ba272005cf71da865a9dbb857315..9dabf376d394bc4f1dd7e6830f753dc64eecda5a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -25,9 +25,7 @@
 #include "dcmtk/dcmdata/dcerror.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
index 0a6a6fd9540d2532c31da2d322de72014d77abaf..c67aaab22b2c64cdedd26f9d9965e7768f0dce99 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2010, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -321,7 +321,7 @@ offile_off_t DcmZLibInputFilter::decompress(const void *buf, offile_off_t buflen
             * (where PDVs always have even length).
             * Everything else generates a warning.
             */
-           DCMDATA_WARN("zlib: " << OFstatic_cast(ulong, count-1) << " pending input bytes in buffer.");
+           DCMDATA_WARN("DcmZLibInputFilter: " << OFstatic_cast(unsigned long, count-1) << " pending input bytes in buffer");
          }
        }
 #endif
@@ -366,7 +366,7 @@ offile_off_t DcmZLibInputFilter::decompress(const void *buf, offile_off_t buflen
                 * (where PDVs always have even length).
                 * Everything else generates a warning.
                 */
-               DCMDATA_WARN("zlib: " << OFstatic_cast(ulong, count-1) << " pending input bytes in buffer.");
+               DCMDATA_WARN("DcmZLibInputFilter: " << OFstatic_cast(unsigned long, count-1) << " pending input bytes in buffer");
              }
           }
 #endif
index 244dbb7b5d46a47c4be4ef01f939dc336147d393..62bf16f2437feb64254a63d43e1dd578bb1c0348 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -1050,10 +1050,11 @@ OFCondition DcmItem::readTagAndLength(DcmInputStream &inStream,
     swapIfNecessary(gLocalByteOrder, byteOrder, &elementTag, 2, 2);
     // tag has been read
     bytesRead = 4;
+    OFString readVR;
     DcmTag newTag(groupTag, elementTag);
     DcmEVR newEVR = newTag.getEVR();
     // check whether tag is private
-    OFBool isPrivate = groupTag & 1;
+    const OFBool isPrivate = groupTag & 1;
 
     /* if the transfer syntax which was passed is an explicit VR syntax and if the current */
     /* item is not a delimitation item (note that delimitation items do not have a VR), go */
@@ -1065,6 +1066,7 @@ OFCondition DcmItem::readTagAndLength(DcmInputStream &inStream,
 
         /* read 2 bytes */
         inStream.read(vrstr, 2);
+        readVR = vrstr;
 
         /* create a corresponding DcmVR object */
         DcmVR vr(vrstr);
@@ -1193,9 +1195,28 @@ OFCondition DcmItem::readTagAndLength(DcmInputStream &inStream,
         if ((vrSize > 1) && (valueLength % vrSize != 0))
         {
             /* warning is only reported for standard, fixed-size VRs that require more than 1 byte per value */
-            DCMDATA_WARN("DcmItem: Length of element " << newTag << " is not a multiple of " << vrSize << " (VR=" << vr.getVRName() << ")");
+            if (valueLength == DCM_UndefinedLength)
+            {
+                /* check whether the VR supports undefined length for the length field */
+                if (!vr.supportsUndefinedLength())
+                {
+                    DCMDATA_WARN("DcmItem: Dubious use of undefined length for element " << newTag
+                        << " with VR=" << vr.getVRName());
+                }
+            } else {
+                DCMDATA_WARN("DcmItem: Length of element " << newTag << " is not a multiple of " << vrSize
+                    << " (VR=" << vr.getVRName() << ")");
+            }
         }
     }
+    /* check whether the correct VR is used for PixelData element in encapsulated format */
+    if ((newTag == DCM_PixelData) && xferSyn.usesEncapsulatedFormat() &&
+        (valueLength == DCM_UndefinedLength) && (readVR != "OB") /* this is the VR that was read */)
+    {
+        DCMDATA_WARN("DcmItem: Wrong VR for encapsulated PixelData " << newTag
+            << ", should be 'OB' instead of '" << readVR << "'");
+    }
+
     /* if the value in the length field is odd, print an error message */
     if ((valueLength & 1) && (valueLength != DCM_UndefinedLength))
     {
@@ -2413,7 +2434,7 @@ OFCondition DcmItem::findAndGetElements(const DcmTagKey &tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetString(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetString(const DcmTagKey &tagKey,
                                       const char *&value,
                                       const OFBool searchIntoSub)
 {
@@ -2432,7 +2453,7 @@ OFCondition DcmItem::findAndGetString(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetString(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetString(const DcmTagKey &tagKey,
                                       const char *&value,
                                       Uint32 &length,
                                       const OFBool searchIntoSub)
@@ -2455,7 +2476,7 @@ OFCondition DcmItem::findAndGetString(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetOFString(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetOFString(const DcmTagKey &tagKey,
                                         OFString &value,
                                         const unsigned long pos,
                                         const OFBool searchIntoSub)
@@ -2475,7 +2496,7 @@ OFCondition DcmItem::findAndGetOFString(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetOFStringArray(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetOFStringArray(const DcmTagKey &tagKey,
                                              OFString &value,
                                              const OFBool searchIntoSub)
 {
@@ -2494,7 +2515,7 @@ OFCondition DcmItem::findAndGetOFStringArray(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint8(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint8(const DcmTagKey &tagKey,
                                      Uint8 &value,
                                      const unsigned long pos,
                                      const OFBool searchIntoSub)
@@ -2514,7 +2535,7 @@ OFCondition DcmItem::findAndGetUint8(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint8Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint8Array(const DcmTagKey &tagKey,
                                           const Uint8 *&value,
                                           unsigned long *count,
                                           const OFBool searchIntoSub)
@@ -2544,7 +2565,7 @@ OFCondition DcmItem::findAndGetUint8Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint16(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint16(const DcmTagKey &tagKey,
                                       Uint16 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2564,7 +2585,7 @@ OFCondition DcmItem::findAndGetUint16(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint16Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint16Array(const DcmTagKey &tagKey,
                                            const Uint16 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2597,7 +2618,7 @@ OFCondition DcmItem::findAndGetUint16Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint16(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint16(const DcmTagKey &tagKey,
                                       Sint16 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2617,7 +2638,7 @@ OFCondition DcmItem::findAndGetSint16(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint16Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint16Array(const DcmTagKey &tagKey,
                                            const Sint16 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2647,7 +2668,7 @@ OFCondition DcmItem::findAndGetSint16Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint32(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint32(const DcmTagKey &tagKey,
                                       Uint32 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2667,7 +2688,7 @@ OFCondition DcmItem::findAndGetUint32(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint32Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint32Array(const DcmTagKey &tagKey,
                                            const Uint32 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2697,7 +2718,7 @@ OFCondition DcmItem::findAndGetUint32Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint32(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint32(const DcmTagKey &tagKey,
                                       Sint32 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2717,7 +2738,7 @@ OFCondition DcmItem::findAndGetSint32(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint32Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint32Array(const DcmTagKey &tagKey,
                                            const Sint32 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2747,7 +2768,7 @@ OFCondition DcmItem::findAndGetSint32Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint64(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint64(const DcmTagKey &tagKey,
                                       Uint64 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2767,7 +2788,7 @@ OFCondition DcmItem::findAndGetUint64(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetUint64Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetUint64Array(const DcmTagKey &tagKey,
                                            const Uint64 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2797,7 +2818,7 @@ OFCondition DcmItem::findAndGetUint64Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint64(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint64(const DcmTagKey &tagKey,
                                       Sint64 &value,
                                       const unsigned long pos,
                                       const OFBool searchIntoSub)
@@ -2817,7 +2838,7 @@ OFCondition DcmItem::findAndGetSint64(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetSint64Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetSint64Array(const DcmTagKey &tagKey,
                                            const Sint64 *&value,
                                            unsigned long *count,
                                            const OFBool searchIntoSub)
@@ -2847,7 +2868,7 @@ OFCondition DcmItem::findAndGetSint64Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetLongInt(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetLongInt(const DcmTagKey &tagKey,
                                        long int &value,
                                        const unsigned long pos,
                                        const OFBool searchIntoSub)
@@ -2897,7 +2918,7 @@ OFCondition DcmItem::findAndGetLongInt(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetFloat32(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetFloat32(const DcmTagKey &tagKey,
                                        Float32 &value,
                                        const unsigned long pos,
                                        const OFBool searchIntoSub)
@@ -2917,7 +2938,7 @@ OFCondition DcmItem::findAndGetFloat32(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetFloat32Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetFloat32Array(const DcmTagKey &tagKey,
                                             const Float32 *&value,
                                             unsigned long *count,
                                             const OFBool searchIntoSub)
@@ -2947,7 +2968,7 @@ OFCondition DcmItem::findAndGetFloat32Array(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetFloat64(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetFloat64(const DcmTagKey &tagKey,
                                        Float64 &value,
                                        const unsigned long pos,
                                        const OFBool searchIntoSub)
@@ -2967,7 +2988,7 @@ OFCondition DcmItem::findAndGetFloat64(const DcmTagKey& tagKey,
 }
 
 
-OFCondition DcmItem::findAndGetFloat64Array(const DcmTagKeytagKey,
+OFCondition DcmItem::findAndGetFloat64Array(const DcmTagKey &tagKey,
                                             const Float64 *&value,
                                             unsigned long *count,
                                             const OFBool searchIntoSub)
@@ -3095,7 +3116,7 @@ OFCondition DcmItem::findAndGetSequenceItem(const DcmTagKey &seqTagKey,
 
 /* --- findOrCreate functions: find an element or create a new one --- */
 
-OFCondition DcmItem::findOrCreateSequenceItem(const DcmTagseqTag,
+OFCondition DcmItem::findOrCreateSequenceItem(const DcmTag &seqTag,
                                               DcmItem *&item,
                                               const signed long itemNum)
 {
@@ -3270,7 +3291,7 @@ OFCondition DcmItem::findAndDeleteSequenceItem(const DcmTagKey &seqTagKey,
 
 /* --- putAndInsert functions: put value and insert new element --- */
 
-OFCondition DcmItem::putAndInsertString(const DcmTagtag,
+OFCondition DcmItem::putAndInsertString(const DcmTag &tag,
                                         const char *value,
                                         const OFBool replaceOld)
 {
@@ -3281,7 +3302,7 @@ OFCondition DcmItem::putAndInsertString(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertString(const DcmTagtag,
+OFCondition DcmItem::putAndInsertString(const DcmTag &tag,
                                         const char *value,
                                         const Uint32 length,
                                         const OFBool replaceOld)
@@ -3409,7 +3430,7 @@ OFCondition DcmItem::putAndInsertString(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertOFStringArray(const DcmTagtag,
+OFCondition DcmItem::putAndInsertOFStringArray(const DcmTag &tag,
                                                const OFString &value,
                                                const OFBool replaceOld)
 {
@@ -3493,7 +3514,7 @@ OFCondition DcmItem::putAndInsertOFStringArray(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertUint8Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertUint8Array(const DcmTag &tag,
                                             const Uint8 *value,
                                             const unsigned long count,
                                             const OFBool replaceOld)
@@ -3545,7 +3566,7 @@ OFCondition DcmItem::putAndInsertUint8Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertUint16(const DcmTagtag,
+OFCondition DcmItem::putAndInsertUint16(const DcmTag &tag,
                                         const Uint16 value,
                                         const unsigned long pos,
                                         const OFBool replaceOld)
@@ -3587,7 +3608,7 @@ OFCondition DcmItem::putAndInsertUint16(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertUint16Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertUint16Array(const DcmTag &tag,
                                              const Uint16 *value,
                                              const unsigned long count,
                                              const OFBool replaceOld)
@@ -3600,13 +3621,13 @@ OFCondition DcmItem::putAndInsertUint16Array(const DcmTag& tag,
         case EVR_AT:
             elem = new DcmAttributeTag(tag);
             break;
+        case EVR_US:
+            elem = new DcmUnsignedShort(tag);
+            break;
         case EVR_lt:
         case EVR_OW:
             elem = new DcmOtherByteOtherWord(tag);
             break;
-        case EVR_US:
-            elem = new DcmUnsignedShort(tag);
-            break;
         case EVR_ox:
             /* special handling */
             if (tag == DCM_PixelData)
@@ -3650,7 +3671,7 @@ OFCondition DcmItem::putAndInsertUint16Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertSint16(const DcmTagtag,
+OFCondition DcmItem::putAndInsertSint16(const DcmTag &tag,
                                         const Sint16 value,
                                         const unsigned long pos,
                                         const OFBool replaceOld)
@@ -3692,7 +3713,7 @@ OFCondition DcmItem::putAndInsertSint16(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertSint16Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertSint16Array(const DcmTag &tag,
                                              const Sint16 *value,
                                              const unsigned long count,
                                              const OFBool replaceOld)
@@ -3734,7 +3755,7 @@ OFCondition DcmItem::putAndInsertSint16Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertUint32(const DcmTagtag,
+OFCondition DcmItem::putAndInsertUint32(const DcmTag &tag,
                                         const Uint32 value,
                                         const unsigned long pos,
                                         const OFBool replaceOld)
@@ -3774,7 +3795,7 @@ OFCondition DcmItem::putAndInsertUint32(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertUint32Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertUint32Array(const DcmTag &tag,
                                              const Uint32 *value,
                                              const unsigned long count,
                                              const OFBool replaceOld)
@@ -3784,12 +3805,12 @@ OFCondition DcmItem::putAndInsertUint32Array(const DcmTag& tag,
     DcmElement *elem = NULL;
     switch(tag.getEVR())
     {
-        case EVR_OL:
-            elem = new DcmOtherLong(tag);
-            break;
         case EVR_UL:
             elem = new DcmUnsignedLong(tag);
             break;
+        case EVR_OL:
+            elem = new DcmOtherLong(tag);
+            break;
         case EVR_UNKNOWN:
             /* Unknown VR, e.g. tag not found in data dictionary */
             status = EC_UnknownVR;
@@ -3814,7 +3835,7 @@ OFCondition DcmItem::putAndInsertUint32Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertSint32(const DcmTagtag,
+OFCondition DcmItem::putAndInsertSint32(const DcmTag &tag,
                                         const Sint32 value,
                                         const unsigned long pos,
                                         const OFBool replaceOld)
@@ -3851,7 +3872,7 @@ OFCondition DcmItem::putAndInsertSint32(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertSint32Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertSint32Array(const DcmTag &tag,
                                              const Sint32 *value,
                                              const unsigned long count,
                                              const OFBool replaceOld)
@@ -3888,7 +3909,161 @@ OFCondition DcmItem::putAndInsertSint32Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertFloat32(const DcmTag& tag,
+OFCondition DcmItem::putAndInsertUint64(const DcmTag &tag,
+                                        const Uint64 value,
+                                        const unsigned long pos,
+                                        const OFBool replaceOld)
+{
+    OFCondition status = EC_Normal;
+    /* create new element */
+    DcmElement *elem = NULL;
+    switch(tag.getEVR())
+    {
+        case EVR_UV:
+            elem = new DcmUnsigned64bitVeryLong(tag);
+            break;
+        case EVR_OV:
+            elem = new DcmOther64bitVeryLong(tag);
+            break;
+        case EVR_UNKNOWN:
+            /* Unknown VR, e.g. tag not found in data dictionary */
+            status = EC_UnknownVR;
+            break;
+        default:
+            status = EC_IllegalCall;
+            break;
+    }
+    if (elem != NULL)
+    {
+        /* put value */
+        status = elem->putUint64(value, pos);
+        /* insert into dataset/item */
+        if (status.good())
+            status = insert(elem, replaceOld);
+        /* could not be inserted, therefore, delete it immediately */
+        if (status.bad())
+            delete elem;
+    } else if (status.good())
+        status = EC_MemoryExhausted;
+    return status;
+}
+
+
+OFCondition DcmItem::putAndInsertUint64Array(const DcmTag &tag,
+                                             const Uint64 *value,
+                                             const unsigned long count,
+                                             const OFBool replaceOld)
+{
+    OFCondition status = EC_Normal;
+    /* create new element */
+    DcmElement *elem = NULL;
+    switch(tag.getEVR())
+    {
+        case EVR_UV:
+            elem = new DcmUnsigned64bitVeryLong(tag);
+            break;
+        case EVR_OV:
+            elem = new DcmOther64bitVeryLong(tag);
+            break;
+        case EVR_UNKNOWN:
+            /* Unknown VR, e.g. tag not found in data dictionary */
+            status = EC_UnknownVR;
+            break;
+        default:
+            status = EC_IllegalCall;
+            break;
+    }
+    if (elem != NULL)
+    {
+        /* put value */
+        status = elem->putUint64Array(value, count);
+        /* insert into dataset/item */
+        if (status.good())
+            status = insert(elem, replaceOld);
+        /* could not be inserted, therefore, delete it immediately */
+        if (status.bad())
+            delete elem;
+    } else if (status.good())
+        status = EC_MemoryExhausted;
+    return status;
+}
+
+
+OFCondition DcmItem::putAndInsertSint64(const DcmTag &tag,
+                                        const Sint64 value,
+                                        const unsigned long pos,
+                                        const OFBool replaceOld)
+{
+    OFCondition status = EC_Normal;
+    /* create new element */
+    DcmElement *elem = NULL;
+    switch(tag.getEVR())
+    {
+        case EVR_SV:
+            elem = new DcmSigned64bitVeryLong(tag);
+            break;
+        case EVR_UNKNOWN:
+            /* Unknown VR, e.g. tag not found in data dictionary */
+            status = EC_UnknownVR;
+            break;
+        default:
+            status = EC_IllegalCall;
+            break;
+    }
+    if (elem != NULL)
+    {
+        /* put value */
+        status = elem->putSint64(value, pos);
+        /* insert into dataset/item */
+        if (status.good())
+            status = insert(elem, replaceOld);
+        /* could not be inserted, therefore, delete it immediately */
+        if (status.bad())
+            delete elem;
+    } else if (status.good())
+        status = EC_MemoryExhausted;
+    return status;
+}
+
+
+OFCondition DcmItem::putAndInsertSint64Array(const DcmTag &tag,
+                                             const Sint64 *value,
+                                             const unsigned long count,
+                                             const OFBool replaceOld)
+{
+    OFCondition status = EC_Normal;
+    /* create new element */
+    DcmElement *elem = NULL;
+    switch(tag.getEVR())
+    {
+        case EVR_SV:
+            elem = new DcmSigned64bitVeryLong(tag);
+            break;
+        case EVR_UNKNOWN:
+            /* Unknown VR, e.g. tag not found in data dictionary */
+            status = EC_UnknownVR;
+            break;
+        default:
+            status = EC_IllegalCall;
+            break;
+    }
+    if (elem != NULL)
+    {
+        /* put value */
+        status = elem->putSint64Array(value, count);
+        /* insert into dataset/item */
+        if (status.good())
+            status = insert(elem, replaceOld);
+        /* could not be inserted, therefore, delete it immediately */
+        if (status.bad())
+            delete elem;
+    } else if (status.good())
+        status = EC_MemoryExhausted;
+    return status;
+}
+
+
+OFCondition DcmItem::putAndInsertFloat32(const DcmTag &tag,
                                          const Float32 value,
                                          const unsigned long pos,
                                          const OFBool replaceOld)
@@ -3928,7 +4103,7 @@ OFCondition DcmItem::putAndInsertFloat32(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertFloat32Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertFloat32Array(const DcmTag &tag,
                                               const Float32 *value,
                                               const unsigned long count,
                                               const OFBool replaceOld)
@@ -3968,7 +4143,7 @@ OFCondition DcmItem::putAndInsertFloat32Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertFloat64(const DcmTagtag,
+OFCondition DcmItem::putAndInsertFloat64(const DcmTag &tag,
                                          const Float64 value,
                                          const unsigned long pos,
                                          const OFBool replaceOld)
@@ -4011,7 +4186,7 @@ OFCondition DcmItem::putAndInsertFloat64(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertFloat64Array(const DcmTagtag,
+OFCondition DcmItem::putAndInsertFloat64Array(const DcmTag &tag,
                                               const Float64 *value,
                                               const unsigned long count,
                                               const OFBool replaceOld)
@@ -4051,7 +4226,7 @@ OFCondition DcmItem::putAndInsertFloat64Array(const DcmTag& tag,
 }
 
 
-OFCondition DcmItem::putAndInsertTagKey(const DcmTagtag,
+OFCondition DcmItem::putAndInsertTagKey(const DcmTag &tag,
                                         const DcmTagKey &value,
                                         const unsigned long pos,
                                         const OFBool replaceOld)
@@ -4091,7 +4266,7 @@ OFCondition DcmItem::putAndInsertTagKey(const DcmTag& tag,
 // ********************************
 
 
-OFCondition DcmItem::insertEmptyElement(const DcmTagtag,
+OFCondition DcmItem::insertEmptyElement(const DcmTag &tag,
                                         const OFBool replaceOld)
 {
     OFCondition status = EC_Normal;
@@ -4375,11 +4550,11 @@ void DcmItem::updateSpecificCharacterSet(OFCondition &status,
                 // delete Specific Character Set (0008,0005) data element (type 1C)
                 if (findAndDeleteElement(DCM_SpecificCharacterSet, OFFalse /*allOccurrences*/, OFFalse /*searchIntoSub*/).good())
                 {
-                    DCMDATA_DEBUG("DcmItem::convertCharacterSet() deleted element SpecificCharacterSet "
+                    DCMDATA_DEBUG("DcmItem::updateSpecificCharacterSet() deleted element SpecificCharacterSet "
                         << DCM_SpecificCharacterSet << " during the conversion to " << encoding << " encoding");
                 }
             } else {
-                DCMDATA_DEBUG("DcmItem::convertCharacterSet() updating value of element SpecificCharacterSet "
+                DCMDATA_DEBUG("DcmItem::updateSpecificCharacterSet() updating value of element SpecificCharacterSet "
                     << DCM_SpecificCharacterSet << " to '" << toCharset << "'");
                 // update/set value of Specific Character Set (0008,0005) if needed
                 status = putAndInsertOFStringArray(DCM_SpecificCharacterSet, toCharset);
@@ -4757,13 +4932,13 @@ OFCondition DcmItem::newDicomElement(DcmElement *&newElement,
                     if (dcmIgnoreParsingErrors.get())
                     {
                         // ignore parse error, keep VR unchanged
-                        DCMDATA_WARN("DcmItem: VOI LUT Sequence with VR=OW and explicit length encountered.");
+                        DCMDATA_WARN("DcmItem: VOI LUT Sequence with VR=OW and explicit length encountered");
                         newElement = new DcmOtherByteOtherWord(tag, length);
                     }
                     else
                     {
                         // bail out with an error
-                        DCMDATA_ERROR("DcmItem: VOI LUT Sequence with VR=OW and explicit length encountered.");
+                        DCMDATA_ERROR("DcmItem: VOI LUT Sequence with VR=OW and explicit length encountered");
                         l_error = EC_VOI_LUT_OBOW;
                     }
                 }
@@ -4775,8 +4950,11 @@ OFCondition DcmItem::newDicomElement(DcmElement *&newElement,
                 // special handling for private pixel data (compressed or uncompressed)
                 if (newTag.getEVR() == EVR_px)
                 {
-                    DCMDATA_WARN("Found private element " << tag << " with VR " << tag.getVRName()
-                        << " and undefined length, reading a pixel sequence according to data dictionary");
+                    if (length == DCM_UndefinedLength)
+                    {
+                        DCMDATA_WARN("DcmItem: Found private element " << tag << " with VR=" << tag.getVRName()
+                            << " and undefined length, reading a pixel sequence according to data dictionary");
+                    }
                     newElement = new DcmPixelData(tag, length);
                 }
             }
@@ -4826,10 +5004,10 @@ OFCondition DcmItem::newDicomElement(DcmElement *&newElement,
                 newTag.setVR(DcmVR(EVR_SQ)); // on writing we will handle this element as SQ, not UN
                 if (dcmEnableCP246Support.get())
                 {
-                    DCMDATA_WARN("Found element " << newTag << " with VR UN and undefined length, "
+                    DCMDATA_WARN("DcmItem: Found element " << newTag << " with VR=UN and undefined length, "
                         << "reading a sequence with transfer syntax LittleEndianImplicit (CP-246)");
                 } else {
-                    DCMDATA_WARN("Found element " << newTag << " with VR UN and undefined length");
+                    DCMDATA_WARN("DcmItem: Found element " << newTag << " with VR=UN and undefined length");
                 }
                 newElement = new DcmSequenceOfItems(newTag, length, dcmEnableCP246Support.get());
             } else {
index dbbbe9309b099db8c4d0ab4f2d2952b9ed66f48b..f23ab5258c79901b176225d3d5c22cd7a0276ea5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2023, OFFIS e.V.
+ *  Copyright (C) 2016-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmdata/dcjson.h"
 #include "dcmtk/ofstd/ofdefine.h"
 #include "dcmtk/ofstd/ofstring.h"
+#include "dcmtk/ofstd/offile.h"
+#include "dcmtk/ofstd/ofsha256.h"
+#include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/dcmdata/dctypes.h"
+#include "dcmtk/dcmdata/dcerror.h"
 
 #include <cassert>
 
@@ -57,7 +62,7 @@ void DcmJsonFormat::escapeControlCharacters(STD_NAMESPACE ostream &out, const OF
             out << "\\f";
             break;
         default:
-            //escapes all other control characters
+            // escapes all other control characters
             if (c >= '\0' && c < ' ')
             {
                 out << "\\u" << STD_NAMESPACE hex
@@ -79,7 +84,7 @@ void DcmJsonFormat::normalizeDecimalString(OFString &value)
     // These are permitted in DICOM but not in JSON.
     size_t pos;
     while (OFString_npos != (pos = value.find('+')))
-      value.erase(pos,1);
+        value.erase(pos,1);
 
     // check if the first character is a minus sign.
     // if so, remove it and set "minus" to true
@@ -114,28 +119,27 @@ void DcmJsonFormat::normalizeDecimalString(OFString &value)
     // with a period
     if (OFString_npos != (pos = value.find('.')))
     {
-      if (pos == value.length() -1)
-      {
-        // number ends with a period. Add a zero
-        value.append("0");
-      }
-      else if ((value[pos+1] < '0') || (value[pos+1] > '9'))
-      {
-        // no digit after period. Insert a zero
-        value.insert(pos+1, "0");
-      }
+        if (pos == value.length() -1)
+        {
+            // number ends with a period. Add a zero
+            value.append("0");
+        }
+        else if ((value[pos+1] < '0') || (value[pos+1] > '9'))
+        {
+            // no digit after period. Insert a zero
+            value.insert(pos+1, "0");
+        }
     }
-
 }
 
 // Formats the number to JSON standard as IntegerString
 void DcmJsonFormat::normalizeIntegerString(OFString &value)
 {
     // remove all plus characters that may occur in the string.
-    // These are permitted in DICOM but not in Json.
+    // These are permitted in DICOM but not in JSON.
     size_t pos;
     while (OFString_npos != (pos = value.find('+')))
-      value.erase(pos,1);
+        value.erase(pos,1);
 
     OFBool minus = OFFalse;
 
@@ -243,19 +247,173 @@ void DcmJsonFormat::printNextArrayElementPrefix(STD_NAMESPACE ostream &out)
     out << "," << newline() << indent();
 }
 
-// Method for holding and determine if BulkDataURI should be printed.
-// This also manipulate uri String, if BulkDataURI should be printed.
-OFBool DcmJsonFormat::asBulkDataURI(const DcmTagKey& /*tag*/, OFString& /*uri*/)
+OFBool DcmJsonFormat::asBulkDataURI(const DcmTagKey& /*tag*/, Uint32 len) const
+{
+    // return OFFalse if bulk data is disabled
+    if (minBulkDataSize < 0) return OFFalse;
+
+    // return OFFalse if the attribute value is too small
+    size_t minSize = (OFstatic_cast(size_t, minBulkDataSize));
+    if ((minSize << 10) > len) return OFFalse;
+
+    return OFTrue;
+}
+
+void  DcmJsonFormat::getBulkDataDirectory(OFString& directory) const
+{
+    directory = bulkDataDirectory;
+}
+
+void  DcmJsonFormat::getBulkDataURIPrefix(OFString& prefix) const
+{
+    prefix = bulkDataURIPrefix;
+}
+
+void DcmJsonFormat::setMinBulkSize(ssize_t min_bulk_size)
 {
-    return OFFalse;
+    minBulkDataSize = min_bulk_size;
 }
 
-//Class for formatted output
+void DcmJsonFormat::setBulkURIPrefix(const char *bulk_uri_prefix)
+{
+    if (bulk_uri_prefix)
+    {
+        bulkDataURIPrefix = bulk_uri_prefix;
+
+        // if the URI prefix does not end with "/", silently add this character
+        if ((bulkDataURIPrefix.length() > 0) && (bulkDataURIPrefix[bulkDataURIPrefix.length()-1] != '/'))
+        {
+            bulkDataURIPrefix.append("/");
+        }
+    }
+    else bulkDataURIPrefix = "";
+}
+
+void DcmJsonFormat::setBulkDir(const char *bulk_dir)
+{
+    if (bulk_dir)
+    {
+        bulkDataDirectory = bulk_dir;
+    }
+    else bulkDataDirectory = ".";
+
+    // if the directory name does not end with a path separator, silently add one
+    if ((bulkDataDirectory.length() > 0) && (bulkDataDirectory[bulkDataDirectory.length()-1] != '/') && (bulkDataDirectory[bulkDataDirectory.length()-1] != PATH_SEPARATOR))
+    {
+        bulkDataDirectory.append(1, PATH_SEPARATOR);
+    }
+}
+
+
+OFCondition DcmJsonFormat::writeBulkData(
+    STD_NAMESPACE ostream &out,
+    const DcmTagKey& /*tagkey*/,
+    Uint32 len,
+    Uint8 *byteValues,
+    const char *extension)
+{
+    /* for an empty value field, we do not need to do anything */
+    if (len > 0)
+    {
+        OFString bulkDataURI;
+        getBulkDataURIPrefix(bulkDataURI);
+
+        /* compute SHA-256 checksum */
+        size_t vallen = OFstatic_cast(size_t, len);
+        OFSHA256 sha256;
+        Uint8 hash[32];
+        sha256.update(byteValues, vallen);
+        sha256.final(hash);
+
+        /* determine filename and path */
+        OFString bulkname;
+        char hashstring[3];
+        for (int i=0; i < 32; ++i)
+        {
+            OFStandard::snprintf(hashstring, sizeof(hashstring), "%02x", hash[i]);
+            bulkname.append(hashstring);
+        }
+        if (extension) bulkname.append(extension);
+
+        OFString bulkpath;
+        getBulkDataDirectory(bulkpath);
+
+        /* bulkpath already ends with a path separator, just add the file name */
+        bulkpath.append(bulkname);
+
+        /* check if file already exists. In this case, the file content is the same
+         * we would create now since the SHA-256 checksum is the same. So we can just
+         * use the existing file.
+         */
+        if (! OFStandard::fileExists(bulkpath))
+        {
+            OFFile bulkfile;
+            if (! bulkfile.fopen(bulkpath.c_str(), "wb"))
+            {
+                DCMDATA_ERROR("Unable to create bulk data file '" << bulkpath << "'");
+                return EC_CannotWriteBulkDataFile;
+            }
+            if (vallen != bulkfile.fwrite(byteValues, 1, vallen))
+            {
+                DCMDATA_ERROR("Unable to write bulk data to file '" << bulkpath << "'");
+                return EC_CannotWriteBulkDataFile;
+            }
+            if (bulkfile.fclose())
+            {
+                DCMDATA_ERROR("Unable to close bulk data file '" << bulkpath << "'");
+                return EC_CannotWriteBulkDataFile;
+            }
+        }
+
+        /* return defined BulkDataURI associated with `tagKey` */
+        printBulkDataURIPrefix(out);
+        bulkDataURI.append(bulkname);
+        DcmJsonFormat::printString(out, bulkDataURI);
+    }
+
+    return EC_Normal;
+}
+
+
+OFCondition DcmJsonFormat::writeBinaryAttribute(
+    STD_NAMESPACE ostream &out,
+    const DcmTagKey& tagkey,
+    Uint32 len,
+    Uint8 *byteValues,
+    const char *extension)
+{
+    OFCondition result = EC_Normal;
+
+    /* for an empty value field, we do not need to do anything */
+    if (len > 0)
+    {
+        if (asBulkDataURI(tagkey, len))
+        {
+            result = writeBulkData(out, tagkey, len, byteValues, extension);
+        }
+        else
+        {
+            /* encode binary data as Base64 */
+            printInlineBinaryPrefix(out);
+            out << "\"";
+            /* adjust byte order to little endian */
+            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, len));
+            out << "\"";
+        }
+    }
+
+    return result;
+}
+
+
+// --------------------------------------------------------------------------
+// Class for formatted output
+// --------------------------------------------------------------------------
+
 DcmJsonFormatPretty::DcmJsonFormatPretty(const OFBool printMetaInfo)
 : DcmJsonFormat(printMetaInfo)
 , m_IndentionLevel(0)
 {
-
 }
 
 void DcmJsonFormatPretty::printIndention(STD_NAMESPACE ostream& out)
@@ -285,22 +443,26 @@ OFString DcmJsonFormatPretty::space()
     return " ";
 }
 
+// --------------------------------------------------------------------------
+// Class for unformatted output
+// --------------------------------------------------------------------------
 
-//Class for unformatted output
 DcmJsonFormatCompact::DcmJsonFormatCompact(const OFBool printMetaInfo)
 : DcmJsonFormat(printMetaInfo)
 {
-
 }
 
 void DcmJsonFormatCompact::printIndention(STD_NAMESPACE ostream& /*out*/)
-{}
+{
+}
 
 void DcmJsonFormatCompact::increaseIndention()
-{}
+{
+}
 
 void DcmJsonFormatCompact::decreaseIndention()
-{}
+{
+}
 
 OFString DcmJsonFormatCompact::newline()
 {
diff --git a/dcmdata/libsrc/dcjsonrd.cc b/dcmdata/libsrc/dcjsonrd.cc
new file mode 100644 (file)
index 0000000..064dc35
--- /dev/null
@@ -0,0 +1,1616 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Tingyan Xu, Marco Eichelberg
+ *
+ *  Purpose: Class for converting JSON DICOM documents to binary DICOM files
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"      /* make sure OS specific configuration is included first */
+#include "dcmtk/dcmdata/dcjsonrd.h"
+#include "dcmtk/ofstd/ofcond.h"         /* for class OFCondition */
+#include "dcmtk/ofstd/offile.h"         /* for class OFFile */
+#include "dcmtk/dcmdata/dcerror.h"      /* for dcmdata logger macros */
+#include "dcmtk/dcmdata/dcfilefo.h"     /* for class DcmFileFormat */
+#include "dcmtk/dcmdata/dcmetinf.h"
+#include "dcmtk/dcmdata/dcdeftag.h"     /* for tag keys */
+#include "dcmtk/dcmdata/dcswap.h"
+#include "dcmtk/dcmdata/dcvrov.h"       /* for DcmOther64bitVeryLong */
+
+#include <climits>                      /* for INT_MAX */
+
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+// Private creator identification string for files
+// containing a list of datasets as a private sequence
+#define JSON2DCM_PRIVATE_RESERVATION "JSON2DCM_LIST_OF_DATASETS"
+
+// Begin with a 1 MByte buffer when reading from stdin.
+// Buffer size will increase if necessary.
+#define JSON2DCM_STDIN_BLOCKSIZE 1048576
+
+
+DcmJSONReader::DcmJSONReader()
+: jsonDataset_(NULL)
+, jsonDatasetLen_(0)
+, tokenArray_(NULL)
+, tokenNumber_(0)
+, ignoreBulkdataURIPolicy_(OFFalse)
+, stopOnErrorPolicy_(OFTrue)
+, ignoreMetaInfoPolicy_(OFFalse)
+, arrayHandlingPolicy_(-1)
+, xferSyntax_(EXS_LittleEndianExplicit)
+, permittedBulkdataDirs_()
+{
+}
+
+
+DcmJSONReader::~DcmJSONReader()
+{
+    clear();
+}
+
+
+void DcmJSONReader::clear()
+{
+    delete[] jsonDataset_;
+    jsonDataset_ = NULL;
+    delete[] tokenArray_;
+    tokenArray_ = NULL;
+    jsonDatasetLen_ = 0;
+    tokenNumber_ = 0;
+}
+
+
+OFCondition DcmJSONReader::readJSONFile(const char *ifname)
+{
+    if (NULL == ifname) return EC_IllegalParameter;
+
+    OFFile jsonFile;
+    if (! jsonFile.fopen(ifname, "rb"))
+    {
+        OFString s("(unknown error code)");
+        jsonFile.getLastErrorString(s);
+        DCMDATA_ERROR("failed to open JSON file '" << ifname << "': " << s);
+        return makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str());
+    }
+
+    // obtain file size
+    const size_t len = OFStandard::getFileSize(ifname);
+    char *jsonString = new (std::nothrow) char[len + 1];
+    if (jsonString == NULL)
+    {
+        DCMDATA_ERROR("out of memory: failed to allocate buffer for JSON file");
+        return EC_MemoryExhausted;
+    }
+
+    // read the whole file to buffer
+    jsonString[len] = '\0';
+    size_t res = jsonFile.fread(jsonString, 1, len);
+    jsonFile.fclose();
+    if (res != len)
+    {
+        OFString s("(unknown error code)");
+        jsonFile.getLastErrorString(s);
+        delete[] jsonString;
+        return makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str());
+    }
+
+    // file was successfully read into buffer. Store the result, and in the process,
+    // clear the token array which is now invalid
+    clear();
+    jsonDataset_ = jsonString;
+    jsonDatasetLen_ = len;
+
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::readJSONFromStdin()
+{
+    size_t bufSize = JSON2DCM_STDIN_BLOCKSIZE;
+    size_t bufFree;
+    size_t bytesInBuffer = 0;
+    size_t readResult;
+    char *jsonString = NULL;;
+    char *oldBuf = NULL;
+    char *writePtr;
+    do
+    {
+        if (jsonString == NULL) jsonString = new (std::nothrow) char[bufSize+1];
+        if (jsonString == NULL)
+        {
+            DCMDATA_ERROR("out of memory: failed to allocate buffer for reading JSON dataset from stdin");
+            delete[] oldBuf;
+            return EC_MemoryExhausted;
+        }
+        if (oldBuf)
+        {
+            memmove(jsonString, oldBuf, bytesInBuffer);
+            delete[] oldBuf;
+            oldBuf = NULL;
+        }
+        writePtr = jsonString + bytesInBuffer;
+        bufFree = bufSize - bytesInBuffer;
+        readResult = fread(writePtr, 1, bufFree, stdin);
+        bytesInBuffer += readResult;
+        bufFree -= readResult;
+        if ((! feof(stdin)) && (bufFree == 0))
+        {
+            // we need more buffer. Double the size.
+            oldBuf = jsonString;
+            jsonString = NULL;
+            bufSize *= 2;
+        }
+        else if (feof(stdin))
+        {
+            jsonString[bytesInBuffer] = '\0';
+
+            // dataset was successfully read into buffer. Store the result, and in the process,
+            // clear the token array which is now invalid
+            clear();
+            jsonDataset_ = jsonString;
+            jsonDatasetLen_ = bytesInBuffer;
+            return EC_Normal;
+        }
+    } while (OFTrue);
+}
+
+
+OFCondition DcmJSONReader::reserveTokens()
+{
+    if ((NULL == jsonDataset_) || (jsonDatasetLen_ < 2))
+        return EC_IllegalCall;
+
+    OFJsmnParser jsmnParser;
+    jsmn_init(&jsmnParser);
+    int tokenNum = jsmn_parse(&jsmnParser, jsonDataset_, jsonDatasetLen_, NULL, 0);
+
+    if (tokenNum <= 0)
+        return EC_InvalidJSONContent;
+
+    // delete old token array, if still present
+    tokenNumber_ = 0;
+    delete[] tokenArray_;
+
+    // allocate one additional token
+    tokenArray_ = new (std::nothrow) OFJsmnToken[tokenNum+1];
+    if (NULL == tokenArray_)
+    {
+        DCMDATA_ERROR("out of memory: failed to allocate JSON token array");
+        return EC_MemoryExhausted;
+    }
+
+    // initialize token array with zeroes
+    memset(tokenArray_, 0, tokenNum * sizeof(OFJsmnToken));
+
+    // fill dummy token at the end of the array with values
+    // that allow the loop in parseElement() to reliably terminate
+    tokenArray_[tokenNum].start = INT_MAX;
+    tokenArray_[tokenNum].end = INT_MAX;
+    tokenArray_[tokenNum].size = 0;
+
+    // finally, store number of tokens
+    tokenNumber_ = tokenNum;
+
+    DCMDATA_TRACE("JSMN tokens reserved: " << tokenNum);
+    return EC_Normal;
+}
+
+
+void DcmJSONReader::getTokenContent(OFString& value, OFJsmnTokenPtr t)
+{
+    int size = t->end - t->start;
+
+    // remember the character immediately following the token
+    char c = jsonDataset_[t->start+size];
+
+    // convert the token string to a null terminated C string
+    jsonDataset_[t->start+size] = '\0';
+
+    // copy token string into output parameter
+    value = jsonDataset_ + t->start;
+
+    // restore array
+    jsonDataset_[t->start+size] = c;
+    return;
+}
+
+
+OFCondition DcmJSONReader::dumpJSONTokenArray()
+{
+    if ((NULL == tokenArray_) || (tokenNumber_ < 1))
+        return EC_IllegalCall;
+
+    const char *json_type;
+    OFString json_value;
+    fprintf(stderr, "============================== BEGIN JSON DUMP ==============================\n");
+    for (int i=0; i < tokenNumber_; ++i)
+    {
+        switch (tokenArray_[i].type)
+        {
+            case JSMN_OBJECT:
+              json_type = "object,    size=";
+              break;
+            case JSMN_ARRAY:
+              json_type = "array,     size=";
+              break;
+            case JSMN_STRING:
+              json_type = "string,    size=";
+              break;
+            case JSMN_PRIMITIVE:
+              json_type = "primitive, size=";
+              break;
+            case JSMN_UNDEFINED:
+            default:
+              json_type = "undefined, size=";
+              break;
+        }
+
+        getTokenContent(json_value, &tokenArray_[i]);
+        fprintf(stderr, "%06d: type=%s%04d,  value=%s\n", i+1, json_type, tokenArray_[i].size, json_value.c_str());
+    }
+    fprintf(stderr, "=============================== END JSON DUMP ===============================\n");
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::parseJSON()
+{
+    if ((NULL == tokenArray_) || (tokenNumber_ < 1))
+        return EC_IllegalCall;
+
+    OFJsmnParser jsmnParser;
+    jsmn_init(&jsmnParser);
+
+    int parsRes = jsmn_parse(&jsmnParser, jsonDataset_, jsonDatasetLen_, tokenArray_, tokenNumber_);
+
+    if (parsRes < 0)
+    {
+       // a parse error in jsmn_parse occurred
+        DCMDATA_ERROR("parse error in JSON file");
+        if (parsRes == JSMN_ERROR_INVAL)
+            return EC_InvalidCharacter;
+            else return EC_InvalidJSONContent;
+    }
+
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::storeInlineBinaryValue(
+    DcmElement& element,
+    Uint8 *data,
+    size_t length)
+{
+    OFCondition result = EC_Normal;
+    if (NULL == data) length = 0;
+    DcmEVR evr = element.getVR();
+    if (evr == EVR_OW)
+    {
+        /* Base64 decoder produces little endian output data, convert to local byte order */
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint16));
+        result = element.putUint16Array(OFreinterpret_cast(Uint16 *, data), OFstatic_cast(Uint32, length / sizeof(Uint16)));
+    }
+    else if (evr == EVR_OF)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Float32));
+        result = element.putFloat32Array(OFreinterpret_cast(Float32 *, data), OFstatic_cast(Uint32, length / sizeof(Float32)));
+    }
+    else if (evr == EVR_OD)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Float64));
+        result = element.putFloat64Array(OFreinterpret_cast(Float64 *, data), OFstatic_cast(Uint32, length / sizeof(Float64)));
+    }
+    else if (evr == EVR_OL)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint32));
+        result = element.putUint32Array(OFreinterpret_cast(Uint32 *, data), OFstatic_cast(Uint32, length / sizeof(Uint32)));
+    }
+    else if (evr == EVR_OV)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint64));
+        result = element.putUint64Array(OFreinterpret_cast(Uint64 *, data), OFstatic_cast(Uint32, length / sizeof(Uint64)));
+    }
+    else if (evr == EVR_OB || evr == EVR_UN)
+    {
+        result = element.putUint8Array(data, OFstatic_cast(Uint32, length));
+    }
+    else
+    {
+        DCMDATA_ERROR("invalid VR Type for inline value");
+        return EC_InvalidVR;
+    }
+
+    if (result.bad())
+    {
+        DCMDATA_ERROR("failed to store inline binary value for DICOM element "  << element.getTag() << ": " << result.text());
+    }
+    return result;
+}
+
+
+OFCondition DcmJSONReader::storeBulkValue(
+    DcmElement& element,
+    Uint8 *data,
+    size_t length)
+{
+    OFCondition result = EC_Normal;
+    if (NULL == data) length = 0;
+    DcmEVR evr = element.getVR();
+
+    if (evr == EVR_OB || evr == EVR_UN)
+    {
+        // sequence of bytes, no byte swapping necessary
+        result = element.putUint8Array(data, OFstatic_cast(Uint32, length));
+    }
+    else if (evr == EVR_DS || evr == EVR_IS || evr == EVR_LT || evr == EVR_ST || evr == EVR_UT || evr == EVR_UC)
+    {
+        // sequence of bytes, no byte swapping necessary
+        result = element.putString(OFreinterpret_cast(char *, data), OFstatic_cast(Uint32, length));
+    }
+    else if (evr == EVR_OW || evr == EVR_US)
+    {
+        // bulk data is always in little endian, convert to local byte order
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint16));
+        result = element.putUint16Array(OFreinterpret_cast(Uint16 *, data), OFstatic_cast(Uint32, length / sizeof(Uint16)));
+    }
+    else if (evr == EVR_SS)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Sint16));
+        result = element.putSint16Array(OFreinterpret_cast(Sint16 *, data), OFstatic_cast(Uint32, length / sizeof(Sint16)));
+    }
+    else if (evr == EVR_OL || evr == EVR_UL)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint32));
+        result = element.putUint32Array(OFreinterpret_cast(Uint32 *, data), OFstatic_cast(Uint32, length / sizeof(Uint32)));
+    }
+    else if (evr == EVR_SL)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Sint32));
+        result = element.putSint32Array(OFreinterpret_cast(Sint32 *, data), OFstatic_cast(Uint32, length / sizeof(Sint32)));
+    }
+    else if (evr == EVR_OV || evr == EVR_UV)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Uint64));
+        result = element.putUint64Array(OFreinterpret_cast(Uint64 *, data), OFstatic_cast(Uint32, length / sizeof(Uint64)));
+    }
+    else if (evr == EVR_SV)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Sint64));
+        result = element.putSint64Array(OFreinterpret_cast(Sint64 *, data), OFstatic_cast(Uint32, length / sizeof(Sint64)));
+    }
+    else if (evr == EVR_FL || evr == EVR_OF)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Float32));
+        result = element.putFloat32Array(OFreinterpret_cast(Float32 *, data), OFstatic_cast(Uint32, length / sizeof(Float32)));
+    }
+    else if (evr == EVR_FD || evr == EVR_OD)
+    {
+        swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, data, OFstatic_cast(Uint32, length), sizeof(Float64));
+        result = element.putFloat64Array(OFreinterpret_cast(Float64 *, data), OFstatic_cast(Uint32, length / sizeof(Float64)));
+    }
+    else
+    {
+        DCMDATA_ERROR("invalid VR Type for bulk data");
+        return EC_InvalidVR;
+    }
+
+    if (result.bad())
+    {
+        DCMDATA_ERROR("failed to store bulk data value for DICOM element "  << element.getTag() << ": " << result.text());
+    }
+    return result;
+}
+
+
+OFCondition DcmJSONReader::processJSONEscapeCharacters(OFString& value)
+{
+    /*
+        \" represents the quotation mark character (U+0022).
+        \\ represents the reverse solidus character (U+005C).
+        \/ represents the solidus character (U+002F).
+        \b represents the backspace character (U+0008).
+        \f represents the form feed character (U+000C).
+        \n represents the line feed character (U+000A).
+        \r represents the carriage return character (U+000D).
+        \t represents the character tabulation character (U+0009).
+    */
+    OFString escapeSeq = "\"\\/bfnrt";
+
+    // find backslash
+    for (size_t backSlash = value.find('\\');
+        backSlash < value.length();
+        backSlash = value.find('\\', backSlash + 1))
+    {
+        if (value.length() < backSlash + 2)
+        {
+            // the given string is shorter than expected. just return the string
+            DCMDATA_ERROR("incomplete JSON escape sequence");
+            return EC_InvalidJSONContent;
+        }
+        char sigChar = value[backSlash + 1];
+        OFString front = value.substr(0, backSlash);
+        OFString escString, back, replacement;
+        unsigned int unicodeCodepoint = 0;
+
+        if (escapeSeq.find(sigChar) < escapeSeq.length())
+        {
+            back = value.substr(backSlash + 2);
+            escString = sigChar;
+
+            switch (sigChar)
+            {
+            case 'b':
+                unicodeCodepoint = 0x0008;
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                break;
+            case 'f':
+                unicodeCodepoint = 0x000C;
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                break;
+            case 'n':
+                unicodeCodepoint = 0x000A;
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                break;
+            case 'r':
+                unicodeCodepoint = 0x000D;
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                break;
+            case 't':
+                unicodeCodepoint = 0x0009;
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                break;
+            default: // \ / "
+                replacement = sigChar;
+                break;
+            }
+        }
+        else
+        {
+            // does not contain the full pattern of "\uXXXX"
+            if (sigChar != 'u' || value.length() < backSlash + 6)
+            {
+                // unknown escape sequence or incomplete unicode code point
+                DCMDATA_ERROR("unknown JSON escape sequence or incomplete Unicode code point");
+                return EC_InvalidJSONContent;
+            }
+
+            escString = value.substr(backSlash + 2, 4);
+            // parse escString to unicodeCodepoint
+            if (sscanf(escString.c_str(), "%x", &unicodeCodepoint) != 1)
+            {
+                // Invalid hex code
+                DCMDATA_ERROR("invalid hex code in JSON escape sequence");
+                return EC_InvalidJSONContent;
+            }
+
+            // convert Unicode codepoint to UTF-8 string
+            if (unicodeCodepoint < 0x80)
+            {
+                // UTF-8 sequence with one byte
+                replacement = OFstatic_cast(char, unicodeCodepoint);
+                back = value.substr(backSlash + 6);
+            }
+            else if (unicodeCodepoint < 0x800)
+            {
+                // UTF-8 sequence with two bytes
+                replacement = OFstatic_cast(char, ((unicodeCodepoint >> 6) & 0x1F) | 0xC0);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 0) & 0x3F) | 0x80);
+                back = value.substr(backSlash + 6);
+            }
+            else if ((unicodeCodepoint >= 0xD800) && ((unicodeCodepoint < 0xE000)))
+            {
+                // UTF-16 surrogate pair consisting two Unicode code points
+                if ((value.length() < backSlash + 12) || (value[backSlash + 6] != '\\') || (value[backSlash + 7] != 'u'))
+                {
+                    DCMDATA_ERROR("invalid JSON UTF-16 surrogate pair escape sequence");
+                    return EC_InvalidJSONContent;
+                }
+
+                escString = value.substr(backSlash + 8, 4);
+                unsigned int unicodeCodepoint2;
+                if (sscanf(escString.c_str(), "%x", &unicodeCodepoint2) != 1)
+                {
+                    // Invalid hex code
+                    DCMDATA_ERROR("invalid hex code in JSON escape sequence");
+                    return EC_InvalidJSONContent;
+                }
+
+                // combine the two UTF-16 surrogates to a single Unicode code point.
+                // The first code point is the high surrogate (D800..DBFF), the second one the low surrogate (DC00..DFFF)
+                unicodeCodepoint = ((unicodeCodepoint - 0xD800) << 10) + unicodeCodepoint2 - 0xDC00 + 0x10000;
+                // UTF-8 sequence with four bytes
+                replacement = OFstatic_cast(char, ((unicodeCodepoint >> 18) & 0x07) | 0xF0);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 12) & 0x3F) | 0x80);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 6) & 0x3F) | 0x80);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 0) & 0x3F) | 0x80);
+                back = value.substr(backSlash + 12);
+            }
+            else
+            {
+                // UTF-8 sequence with three bytes
+                replacement = OFstatic_cast(char, ((unicodeCodepoint >> 12) & 0x0F) | 0xE0);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 6) & 0x3F) | 0x80);
+                replacement += OFstatic_cast(char, ((unicodeCodepoint >> 0) & 0x3F) | 0x80);
+                back = value.substr(backSlash + 6);
+            }
+        }
+        DCMDATA_TRACE("the escaped string [" << escString << "] is parsed to UTF-8:"
+            << replacement << " - unicode:" << std::hex << unicodeCodepoint);
+        value = front + replacement + back;
+    }
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::parseElement(
+    DcmItem* dataset,
+    DcmItem* metaheader,
+    OFJsmnTokenPtr& current)
+{
+    OFCondition result = EC_Normal;
+    DCMDATA_TRACE("element at " << current->start);
+
+    // the key for the element tag has to be a string
+    if (current->type != JSMN_STRING)
+    {
+        DCMDATA_ERROR("not a valid DICOM JSON dataset: element tag must be a JSON string");
+        return EC_InvalidJSONType;
+    }
+
+    DcmTagKey tagkey;
+    result = extractTag(current, tagkey);
+    if (result.bad())
+    {
+        if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+    }
+    DcmTag dcmTag(tagkey);
+
+    // the next token contains the whole element encapsulated into a JSON object.
+    current++;
+    if (current->type != JSMN_OBJECT)
+    {
+        DCMDATA_ERROR("not a valid DICOM JSON dataset: element content must be a JSON object");
+        return EC_InvalidJSONType;
+    }
+
+    // number of attributes for the element
+    int contentSize = current->size;
+    DcmElement* newElem = NULL;
+    current++;
+
+    // examine the attributes
+    OFJsmnTokenPtr vrToken = NULL, valueToken = NULL;
+    OFString valueType;
+    for (int count = 0; count < contentSize; count++)
+    {
+        OFString attrName;
+        getTokenContent(attrName, current);
+        attrName = OFStandard::toLower(attrName);
+        DCMDATA_TRACE("attribute '" << attrName << "' token at " << current->start << " - " << current->end);
+        current++;
+
+        if (attrName == "vr")
+        {
+            if (vrToken == NULL)
+                vrToken = current;
+            else
+                DCMDATA_WARN("attribute '" << attrName << " already present in this JSON object. This token will be ignored");
+        }
+        else
+        {
+            if (attrName == "bulkdatauri" || attrName == "inlinebinary" || attrName == "value")
+            {
+                if (valueToken == NULL)
+                {
+                    valueToken = current;
+                    valueType = attrName;
+                }
+                else
+                    DCMDATA_WARN("attribute '" << attrName << " already present in this JSON object. This token will be ignored");
+            }
+            else
+            {
+                DCMDATA_ERROR("unknown JSON attribute name \"" << attrName << "\"");
+                return EC_InvalidJSONContent;
+            }
+        }
+        // find the next token in the current hierarchie
+        OFJsmnTokenPtr tmpToken = current;
+        while (current->start < tmpToken->end)
+            current++;
+    }
+
+    OFString vr = "";
+    if (vrToken != NULL)
+        getTokenContent(vr, vrToken);
+
+    // create DICOM element
+    result = createElement(newElem, dcmTag, vr);
+    if (result.bad())
+    {
+        if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+    }
+
+    if (valueToken == NULL)
+    {
+        // no content following, element value remains empty
+        DCMDATA_TRACE("no value token for element " << dcmTag << ", using empty value");
+    }
+
+    // bulk data URIs reference a file, download URL or a URN referencing another MIME part in multipart/related structure.
+    // This is not yet supported
+    else if (valueType == "bulkdatauri")
+    {
+        if (ignoreBulkdataURIPolicy_)
+        {
+            // leave the element with BulkdataURI empty
+            DCMDATA_INFO("ignoring BulkdataURI for element: " << dcmTag << ", leaving element empty");
+        }
+        else
+        {
+            // the URI value has to be a JSON string
+            if (valueToken->type != JSMN_STRING)
+            {
+                DCMDATA_ERROR("not a valid DICOM JSON dataset: BulkdataURI value must be a JSON string");
+                delete newElem;
+                return EC_InvalidJSONType;
+            }
+
+            OFString value;
+            getTokenContent(value, valueToken);
+
+            if (isFileURI(value))
+            {
+                // convert URI to file path
+                OFString filePath;
+                OFString filePathNormalized;
+                size_t offset = 0;
+                size_t length = 0;
+                result = fileURItoPath(value, filePath, offset, length);
+                if (result.bad())
+                {
+                    delete newElem;
+                    return result;
+                }
+
+                // normalize file path
+                result = normalizePath(filePath, filePathNormalized);
+                if (result.bad())
+                {
+                    delete newElem;
+                    return result;
+                }
+
+                // check if file path is present in our list of permitted paths
+                if (! bulkdataPathPermitted(filePathNormalized))
+                {
+                    DCMDATA_ERROR("BulkdataURI refers to a directory that is not permitted for bulk data: '" << filePath << "'");
+                    delete newElem;
+                    return EC_InvalidFilename;
+                }
+
+                // read the file content and insert it into the current element
+                result = loadBulkdataFile(*newElem, filePathNormalized, offset, length);
+                if (result.bad())
+                {
+                    delete newElem;
+                    return result;
+                }
+            }
+            else if (isHttpURI(value))
+            {
+                DCMDATA_ERROR("loading Bulkdata from http/https BulkDataURI not yet possible");
+                delete newElem;
+                return EC_UnsupportedURIType;
+            }
+            else
+            {
+                DCMDATA_ERROR("Unsupported BulkDataURI URI type: '" << value << "'");
+                delete newElem;
+                return EC_UnsupportedURIType;
+            }
+        }
+    }
+
+    // inlinebinary - content is base64 encoded
+    else if (valueType == "inlinebinary")
+    {
+        // the base64 value has to be a JSON string
+        if (valueToken->type != JSMN_STRING)
+        {
+            DCMDATA_ERROR("not a valid DICOM JSON dataset: InlineBinary value must be a JSON string");
+            delete newElem;
+            return EC_InvalidJSONType;
+        }
+
+        OFString value;
+        getTokenContent(value, valueToken);
+        Uint8* data = NULL;
+        const size_t length = OFStandard::decodeBase64(value, data);
+        DCMDATA_TRACE("parsing inline binary (" << length << "): " << value << " | " << data);
+        if (length > 0)
+            result = storeInlineBinaryValue(*newElem, data, length);
+
+        /* delete buffer since data is copied into the element */
+        delete[] data;
+        if (result.bad())
+        {
+            if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+        }
+    }
+    else if (valueType == "value")
+    {
+        if (valueToken->type != JSMN_ARRAY)
+        {
+            // the value of the element has to be an array
+            DCMDATA_ERROR("not a valid DICOM JSON dataset: attribute value must be a JSON array");
+            delete newElem;
+            return EC_InvalidJSONType;
+        }
+
+        // Sequence
+        if (newElem->ident() == EVR_SQ)
+        {
+            result = parseSequence(*(OFstatic_cast(DcmSequenceOfItems*, newElem)), valueToken);
+        }
+        else if (newElem->getTag() == DCM_PixelData)
+        {
+            // special handling for pixel data
+            DCMDATA_ERROR("pixel data must not have a 'value' attribute in the DICOM JSON model");
+            delete newElem;
+            return EC_InvalidJSONContent;
+        }
+        else
+        {
+            // parse the value array
+            DCMDATA_TRACE("parsing value array of size " << valueToken->size);
+            result = parseElementValueArray(newElem, valueToken);
+        }
+        if (result.bad())
+        {
+            if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+        }
+    }
+    else
+    {
+        DCMDATA_ERROR("unknown JSON attribute name: " << valueType);
+        delete newElem;
+        return EC_InvalidJSONContent;
+    }
+
+    if (result.good())
+    {
+        // insert the new attribute to the metaheader if the tag is (0002,xxxx), otherwise to the dataset
+        if (dcmTag.getGroup() == 0x0002)
+        {
+            if (ignoreMetaInfoPolicy_ || (metaheader == NULL))
+            {
+                // we ignore meta info elements
+                delete newElem;
+            }
+            else
+            {
+                if (dcmTag.getElement() == 0x0010)
+                {
+                    // this is (0002,0010) TransferSyntaxUID, extract the transfer syntax
+                    OFString value;
+                    newElem->getOFString(value, 0);
+                    xferSyntax_ = DcmXfer(value.c_str()).getXfer();
+                }
+                result = metaheader->insert(newElem, OFFalse /*replaceOld*/);
+            }
+        }
+        else
+        {
+            result = dataset->insert(newElem, OFFalse /*replaceOld*/);
+        }
+        if (result.bad())
+        {
+            DCMDATA_WARN("element " << dcmTag << " found twice in one data set or item, ignoring second entry");
+            delete newElem;
+        }
+    }
+    else // result.bad()
+    {
+        /* delete element if insertion or putting the value failed */
+        delete newElem;
+    }
+    return result;
+}
+
+
+OFCondition DcmJSONReader::extractTag(
+    OFJsmnTokenPtr keyToken,
+    DcmTagKey& tagkey)
+{
+    OFString tagString;
+    getTokenContent(tagString, keyToken);
+    if (tagString.empty() || tagString.size() != 8)
+    {
+        DCMDATA_ERROR("not a valid DICOM JSON dataset: expected attribute tag string with 8 characters, found '" << tagString << "'");
+        return EC_InvalidTag;
+    }
+    unsigned long group, element;
+    OFString gStr = tagString.substr(0, 4);
+    OFString eStr = tagString.substr(4);
+    if (sscanf(gStr.c_str(), "%lx", &group) != 1
+        || sscanf(eStr.c_str(), "%lx", &element) != 1)
+    {
+       DCMDATA_ERROR("not a valid DICOM JSON dataset: attribute tag must consist of two 16-bit hex numbers");
+       return EC_InvalidTag;
+    }
+
+    tagkey.set(OFstatic_cast(Uint16, group), OFstatic_cast(Uint16, element));
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::parseSequence(
+    DcmSequenceOfItems& sequence,
+    OFJsmnTokenPtr& current)
+{
+    OFCondition result = EC_Normal;
+    int sqSize = current->size;
+    int sqStart = current->start;
+
+    DCMDATA_TRACE("sequence start: " << sqStart << " with size: " << sqSize);
+    current++;
+
+    // iterate over sequence items
+    for (int i = 0; i < sqSize; i++)
+    {
+        DCMDATA_TRACE("item " << sqStart << ":" << i << " -- " << current->start);
+
+        // sequence items have to be an object
+        if (current->type != JSMN_OBJECT)
+            return EC_InvalidJSONType;
+
+        // create new sequence item
+        DcmItem* newItem = new DcmItem();
+        if (newItem != NULL)
+        {
+            sequence.insert(newItem);
+
+            // proceed parsing the item content
+            result = parseDataSet(newItem, NULL, current);
+            if (result.bad() && stopOnErrorPolicy_) return result;
+        }
+        DCMDATA_TRACE("item " << sqStart << ":" << i << " end, next up : " << current->start);
+    }
+    DCMDATA_TRACE("sequence end: " << sqStart << "; next element: " << current->start);
+    return result;
+}
+
+
+OFCondition DcmJSONReader::parseDataSet(
+    DcmItem* dataset,
+    DcmItem* metaheader,
+    OFJsmnTokenPtr& current)
+{
+    OFCondition result = EC_Normal;
+
+    // we expext a JSON object that encapsulates the DICOM dataset
+    if (current->type != JSMN_OBJECT)
+    {
+        DCMDATA_ERROR("not a valid DICOM JSON dataset: datasets must be encapsulated in a JSON object");
+        return EC_InvalidJSONType;
+    }
+    int dsSize = current->size;
+    int dsStart = current->start;
+
+    DCMDATA_TRACE("dataset start " << dsStart << " - size: " << dsSize);
+    current++;
+    for (int i = 0; i < dsSize; i++)
+    {
+        // read each entry in the content object as a DICOM element
+        result = parseElement(dataset, metaheader, current);
+        if (result.bad() && stopOnErrorPolicy_) return result;
+    }
+    DCMDATA_TRACE("dataset end " << dsStart << "; next element: " << current->start);
+    return result;
+}
+
+
+
+
+OFCondition DcmJSONReader::parsePersonName(
+    OFString& value,
+    OFJsmnTokenPtr& current)
+{
+    static const char *PersonGroupNames[] = { "Alphabetic", "Ideographic", "Phonetic" };
+
+    OFCondition result;
+    int size = current->size;
+    if (size > 3)
+    {
+        DCMDATA_ERROR("not a valid DICOM JSON dataset: a person name must have at most three component groups");
+        return EC_InvalidJSONType;
+    }
+
+    OFVector<OFString> pn(3);
+    for (int i = 0; i < size; i++)
+    {
+        current++;
+        if (current->type != JSMN_STRING)
+        {
+            DCMDATA_ERROR("not a valid DICOM JSON dataset: PN values must be JSON strings");
+            return EC_InvalidJSONType;
+        }
+
+        OFString key;
+        getTokenContent(key, current);
+        int idx = -1;
+        for (int j = 0; j < 3; j++)
+        {
+            if (key == PersonGroupNames[j])
+            {
+                idx = j;
+                break;
+            }
+        }
+        if (idx < 0)
+        {
+
+            DCMDATA_ERROR("not a valid DICOM JSON dataset: unsupported PN component group type '" << key << "'");
+            return EC_InvalidJSONType;
+        }
+
+        // if pn[idx] is not empty, it will be overwritten.
+        current++;
+        if (current->type != JSMN_STRING)
+        {
+            DCMDATA_ERROR("not a valid DICOM JSON dataset: PN values must be JSON strings");
+            return EC_InvalidJSONType;
+        }
+
+        getTokenContent(pn[idx], current);
+
+        DCMDATA_TRACE("person name (PN) with " << key << " val " << pn[idx]);
+        result = processJSONEscapeCharacters(pn[idx]);
+        if (result.bad())
+        {
+            if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+        }
+    }
+
+    // PN format is: "alphPN=ideoPN=phonPN"
+    if (!pn[0].empty())
+        value += pn[0];
+    if (!pn[1].empty() || !pn[2].empty())
+        value += '=' + pn[1];
+    if (!pn[2].empty())
+        value += '=' + pn[2];
+    DCMDATA_TRACE("PN value " << value);
+    return result;
+}
+
+
+OFCondition DcmJSONReader::parseElementValueArray(
+    DcmElement*& newElem,
+    OFJsmnTokenPtr& current)
+{
+    OFCondition result;
+    OFString vmString;
+    OFString value;
+    int vm = current->size;
+
+    for (int count = 0; count < vm; count++)
+    {
+        value.clear();
+        current++;
+        if (newElem->ident() == EVR_PN)
+        {
+            // special handling for person names (PN)
+            OFString tokenValue;
+            getTokenContent(tokenValue, current);
+            DCMDATA_TRACE("element value array, parsing PN value: " << tokenValue);
+            if (current->type != JSMN_OBJECT)
+            {
+                if (tokenValue == "null")
+                {
+                    value = "";
+                }
+                else
+                {
+                    DCMDATA_ERROR("not a valid DICOM JSON dataset: PN components must be JSON strings or null");
+                    return EC_InvalidJSONType;
+                }
+            }
+            else
+            {
+                result = parsePersonName(value, current);
+                if (result.bad())
+                {
+                    if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+                }
+            }
+            if (count > 0)
+                vmString += '\\';
+            vmString += value;
+        }
+        else if (newElem->ident() == EVR_AT)
+        {
+            // special handling for attribute tags (AT).
+            // DcmAttributeTag::putOFStringArray() expects a format like this: "(0008,0020)\(0008,0030)"
+            if (current->type != JSMN_STRING)
+            {
+                DCMDATA_ERROR("not a valid DICOM JSON dataset: AT values must be JSON strings");
+                return EC_InvalidJSONType;
+            }
+
+            DcmTagKey tagkey;
+            result = extractTag(current, tagkey);
+            if (result.bad())
+            {
+                if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+            }
+            DCMDATA_TRACE("element value array, parsing AT value: " << tagkey.toString());
+
+            if (count > 0)
+                vmString += '\\';
+            vmString += tagkey.toString();
+        }
+        else
+        {
+            // default for all other VRs (numeric and text)
+            if (current->type != JSMN_PRIMITIVE && current->type != JSMN_STRING)
+            {
+                DCMDATA_ERROR("not a valid DICOM JSON dataset: expected number, string or null");
+                return EC_InvalidJSONType;
+            }
+
+            getTokenContent(value, current);
+            if (current->type == JSMN_STRING)
+            {
+                // JSMN_STRING
+                DCMDATA_TRACE("element value array, parsing string value: " << value);
+                result = processJSONEscapeCharacters(value);
+                if (result.bad())
+                {
+                    if (stopOnErrorPolicy_) return result; else result = EC_Normal;
+                }
+            }
+            else
+            {
+                // JSMN_PRIMITIVE, i.e. null, number, or boolean (which should not occur)
+                // Replace "null" by an empty string and keep numbers as they are
+                if (value == "null") value = "";
+            }
+            if (count > 0)
+                vmString += '\\';
+            vmString += value;
+            DCMDATA_TRACE("element value array: all values: " << vmString);
+        }
+    }
+
+    result = newElem->putOFStringArray(vmString);
+    if (result.bad())
+    {
+       DCMDATA_ERROR("failed to store string value for element " << newElem->getTag() << ": " << result.text());
+    }
+    return result;
+}
+
+
+
+
+OFCondition DcmJSONReader::createElement(
+    DcmElement*& newElem,
+    DcmTag& dcmTag,
+    const OFString& vr)
+{
+    OFCondition result = EC_Normal;
+
+    DCMDATA_TRACE("parsing VR: " << vr);
+
+    // convert vr string
+    const DcmVR jsonVR(vr.c_str());
+    if (jsonVR.isUnknown() || jsonVR.isInvalid())
+    {
+        // check whether "vr" attribute exists
+        if (vr.empty() || vr == "")
+        {
+            DCMDATA_WARN("missing 'vr' attribute for " << dcmTag
+                << ", using the tag's VR (" << dcmTag.getVR().getVRName() << ")");
+        }
+        else {
+            DCMDATA_WARN("invalid 'vr' attribute (" << vr << ") for " << dcmTag
+                << ", using the tag's VR (" << dcmTag.getVR().getVRName() << ")");
+        }
+    }
+    else
+    {
+        const DcmEVR dcmEVR = jsonVR.getEVR();
+        const DcmEVR dictionaryEVR = dcmTag.getEVR();
+
+        // Check if the VR is correct and print a warning otherwise.
+        //
+        // Normally, the JSON file and the data dictionary should specify the same
+        // VR for a tag (i.e., dictionaryEVR == dcmEVR), or dictionaryEVR is EVR_UNKNOWN
+        // if the tag is not present in our data dictionary.
+
+        if ((dictionaryEVR != dcmEVR) && (dictionaryEVR != EVR_UNKNOWN) &&
+            // LUTData VR can be US, SS or OW
+            ((dcmTag.getTagKey() != DCM_LUTData) || ((dcmEVR != EVR_US) && (dcmEVR != EVR_SS) && (dcmEVR != EVR_OW))) &&
+            // If the dictionary says "EVR_xs", the VR can either be US or SS
+            ((dictionaryEVR != EVR_xs) || ((dcmEVR != EVR_US) && (dcmEVR != EVR_SS))) &&
+            // If the dictionary says "EVR_ox" (OB/OW) or "EVR_px" (pixel data), the VR can either be OB or OW
+            (((dictionaryEVR != EVR_ox) && (dictionaryEVR != EVR_px)) || ((dcmEVR != EVR_OB) && (dcmEVR != EVR_OW))))
+        {
+            // there are inconsistencies concerning the VR in the JSON file.
+            // print a warning since there may be resulting errors in the DICOM dataset
+            DCMDATA_WARN("element " << dcmTag << " has wrong VR (" << jsonVR.getVRName()
+                << "), correct is '" << dcmTag.getVR().getVRName() << "'");
+        }
+
+        // change the VR to the one specified in the JSON dataset, even if it does not match our dictionary
+        dcmTag.setVR(jsonVR);
+    }
+
+    // create DICOM element with given tag and VR
+    result = DcmItem::newDicomElementWithVR(newElem, dcmTag);
+    if (result.bad())
+    {
+        DCMDATA_ERROR("failed to create DICOM element "  << dcmTag << ": " << result.text());
+    }
+
+    // if this is pixel data, create an empty unencapsulated representation
+    // to make sure that writing the element with empty value will not fail
+    if (dcmTag == DCM_PixelData) newElem->putUint16Array(NULL,0);
+    return result;
+}
+
+
+OFCondition DcmJSONReader::readAndConvertJSONFile(
+    DcmFileFormat& fileformat,
+    const char *ifname)
+{
+    // clear old buffers, in case this object is re-used
+    clear();
+    DcmMetaInfo* metaheader = fileformat.getMetaInfo();
+    DcmDataset* dataset = fileformat.getDataset();
+    OFCondition result;
+
+    // readin the input file to a memory buffer
+    OFString stdinName("-");
+    if (ifname == stdinName)
+        result = readJSONFromStdin();
+        else result = readJSONFile(ifname);
+    if (result.bad()) return result;
+
+    // calculate tokens needed for the parser and allocate tokens
+    result = reserveTokens();
+    if (result.bad()) return result;
+
+    // use the JSON library to parse the string and save it to the token array.
+    result = parseJSON();
+    if (result.bad() && stopOnErrorPolicy_) return result;
+
+    // check if the token array starts with a JSON array or a JSON object
+    OFJsmnTokenPtr current = tokenArray_;
+    if (current->type == JSMN_ARRAY)
+    {
+        if (current->size < 1)
+        {
+            DCMDATA_ERROR("found empty JSON array instead of DICOM JSON dataset");
+            return EC_InvalidJSONContent;
+        }
+        if (current->size == 1)
+        {
+            // this is a JSON array containing a single DICOM dataset.
+            // Silently ignore the array structure and parse the dataset
+            DCMDATA_DEBUG("parsing JSON array containing a single dataset");
+            current++;
+            result = parseDataSet(dataset, metaheader, current);
+        }
+        else
+        {
+            // this is a JSON array containing a multiple DICOM datasets.
+            if (arrayHandlingPolicy_ < 0)
+            {
+                // reject multiple datasets
+                DCMDATA_ERROR("found JSON array containing " << current->size << " DICOM datasets, rejecting conversion");
+                result = EC_InvalidJSONContent;
+            }
+            else if (arrayHandlingPolicy_ == 0)
+            {
+                // Store multiple datasets in a private sequence.
+                DCMDATA_DEBUG("parsing JSON array containing " << current->size << " DICOM datasets");
+                DcmTag private_reservation(0x0009,0x0010, EVR_LO);
+                DcmTag private_sequence(0x0009,0x1000, EVR_SQ);
+                DcmSequenceOfItems *newSQ = new DcmSequenceOfItems(private_sequence);
+                result = dataset->putAndInsertString(private_reservation, JSON2DCM_PRIVATE_RESERVATION);
+                if (result.good()) result = dataset->insert(newSQ);
+                if (result.good()) result = parseSequence(*newSQ, current);
+            }
+            else
+            {
+                // select a single dataset from the array
+                if (arrayHandlingPolicy_ > current->size)
+                {
+                    DCMDATA_ERROR("found JSON array containing " << current->size << " DICOM datasets, cannot store dataset no. " << arrayHandlingPolicy_);
+                    result = EC_InvalidJSONContent;
+                }
+                else
+                {
+                    DCMDATA_DEBUG("selecting dataset " << arrayHandlingPolicy_ << " from JSON array containing " << current->size << " DICOM datasets");
+
+                    // move "current" to the token representing the first dataset
+                    current++;
+
+                    // number of datasets to skip
+                    signed long tokensToSkip = arrayHandlingPolicy_ - 1;
+
+                    // recursively skip tokens including their sub-tokens until we are done
+                    while (tokensToSkip > 0)
+                    {
+                      tokensToSkip += current->size;
+                      current++;
+                      tokensToSkip--;
+                    }
+
+                    // extract the single dataset at the target location
+                    result = parseDataSet(dataset, metaheader, current);
+                }
+            }
+        }
+    }
+    else
+    {
+        // we expect a single dataset here, parseDataSet() will check if it is the right JSON structure
+        DCMDATA_DEBUG("parsing single JSON dataset");
+        result = parseDataSet(dataset, metaheader, current);
+    }
+
+    if (!stopOnErrorPolicy_) result = EC_Normal;
+    return result;
+}
+
+
+OFBool DcmJSONReader::isFileURI(const OFString& uri) const
+{
+    return (uri.substr(0, 6) == "file:/");
+}
+
+
+OFBool DcmJSONReader::isHttpURI(const OFString& uri) const
+{
+    OFString s = uri.substr(0, 8);
+    if (s == "https://") return OFTrue;
+    s.erase(7);
+    return (s == "http://");
+}
+
+
+OFCondition DcmJSONReader::urlDecode(OFString& uri) const
+{
+    size_t pos;
+    unsigned int val = 0;
+    char c;
+    while (OFString_npos != (pos = uri.find("%")))
+    {
+       if (uri.length() + 3 < pos)
+       {
+            DCMDATA_ERROR("incomplete URL code: " << uri.substr(pos, 3));
+            return EC_UnsupportedURIType;
+
+       }
+       c = uri[pos+1];
+       if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
+       {
+            DCMDATA_ERROR("invalid URL code: " << uri.substr(pos, 3));
+            return EC_UnsupportedURIType;
+       }
+
+       c = uri[pos+2];
+       if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
+       {
+            DCMDATA_ERROR("invalid URL code: " << uri.substr(pos, 3));
+            return EC_UnsupportedURIType;
+       }
+
+       if (1 != sscanf(uri.c_str() + pos, "%%%2x", &val))
+       {
+            DCMDATA_ERROR("invalid URL code: " << uri.substr(pos, 3));
+            return EC_UnsupportedURIType;
+       }
+       uri[pos] = OFstatic_cast(char, val);
+       uri.erase(pos+1, 2);
+    }
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::fileURItoPath(const OFString& uri, OFString& filepath, size_t& offset, size_t& length) const
+{
+    // clear output parameters
+    filepath.clear();
+    offset = 0;
+    length = 0;
+
+    // check if this is a file URI at all
+    if ((uri.substr(0, 6) != "file:/") || (uri.length() < 7))
+    {
+        DCMDATA_ERROR("not a file URI: " << uri);
+        return EC_UnsupportedURIType;
+    }
+
+    OFString filePath;
+    OFString params;
+
+    // check if we have URI parameters. If they are present, store them in a separate string.
+    // In any case, remove the "file:" prefix from the path.
+    size_t paramStart = uri.find("?");
+    if (paramStart == OFString_npos)
+    {
+        filePath = uri.substr(5);
+    }
+    else
+    {
+        params = uri.substr(paramStart+1);
+        filePath = uri.substr(5, paramStart-5);
+   }
+
+    OFCondition result = urlDecode(params);
+    if (result.bad()) return result;
+
+    result = urlDecode(filePath);
+    if (result.bad()) return result;
+
+    // check if we have a URI of type "file:/path" or "file://host/path"
+    if (filePath[1] == '/') // we have checked earlier that the URI is long enough for this
+    {
+        // URI type: file://host/path
+        if (filePath.substr(1, 3) == "///")
+        {
+            DCMDATA_ERROR("Access to file URIs for network hosts not supported: " <<  uri);
+            return EC_UnsupportedURIType;
+        }
+
+        // determine length of hostname
+        size_t separator = filePath.find('/', 2);
+        if (separator == OFString_npos)
+        {
+            DCMDATA_ERROR("file URI without path not supported: " <<  uri);
+            return EC_UnsupportedURIType;
+        }
+
+        // separate hostname and path
+        OFString host = filePath.substr(2, separator-2);
+        filePath = filePath.substr(separator);
+        if ((host != "") && (host != "localhost") && (host != "127.0.0.1") && (host != "ip6-localhost") && (host != "::1"))
+        {
+            DCMDATA_ERROR("Access to file URIs for network hosts not supported: " <<  uri);
+            return EC_UnsupportedURIType;
+        }
+    }
+    if (filePath.length() < 2)
+    {
+        DCMDATA_ERROR("file URI without path not supported: " <<  uri);
+        return EC_UnsupportedURIType;
+    }
+
+#ifdef HAVE_WINDOWS_H
+    if ((filePath.length() > 2) && (filePath[2] == ':'))
+    {
+        // first component of the path is a drive name. Remove leading slash.
+        // We don't do this on Posix systems because the colon character is permitted there as a filename component.
+        filePath.erase(0,1);
+    }
+#endif
+
+    // replace '/' in the path by the system specific path separator
+    size_t l = filePath.size();
+    for (size_t i = 0; i < l; ++i)
+    {
+        if (filePath[i] == '/') filePath[i] = PATH_SEPARATOR;
+    }
+
+    // now for the URI parameters...
+    size_t paramSep;
+    OFString currentParam;
+    while (params.length() > 0)
+    {
+        // separate the next parameter
+        paramSep = params.find("&");
+        if (paramSep == OFString_npos)
+        {
+            currentParam = params;
+            params = "";
+        }
+        else
+        {
+            currentParam = params.substr(0, paramSep);
+            params = params.substr(paramSep + 1);
+        }
+        if (currentParam.substr(0,7) == "offset=")
+        {
+            // convert offset
+            unsigned long ll = 0;
+            currentParam.erase(0,7);
+            if ((OFString_npos != currentParam.find_first_not_of("0123456789")) || (1 != sscanf(currentParam.c_str(), "%lu", &ll)))
+            {
+                DCMDATA_ERROR("Invalid value for URI parameter 'offset': " <<  currentParam);
+                return EC_UnsupportedURIType;
+            }
+            offset = OFstatic_cast(size_t, ll);
+        }
+        else if (currentParam.substr(0,7) == "length=")
+        {
+            // convert length
+            unsigned long ll = 0;
+            currentParam.erase(0,7);
+            if ((OFString_npos != currentParam.find_first_not_of("0123456789")) || (1 != sscanf(currentParam.c_str(), "%lu", &ll)))
+            {
+                DCMDATA_ERROR("Invalid value for URI parameter 'length': " <<  currentParam);
+                return EC_UnsupportedURIType;
+            }
+            length = OFstatic_cast(size_t, ll);
+        }
+        else
+        {
+          DCMDATA_ERROR("'file' URI with unsupported parameter '" << currentParam << "': " <<   uri);
+          return EC_UnsupportedURIType;
+        }
+    }
+    filepath = filePath;
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::normalizePath(const OFString& filepath_in, OFString& filepath_out) const
+{
+    filepath_out.clear();
+#ifdef HAVE_WINDOWS_H
+    char buf[32768];
+
+    // resolve a relative path to an absolute path
+    DWORD res = GetFullPathNameA(filepath_in.c_str(), 32768, buf, NULL);
+    if ((res == 0) || (res > 32768))
+    {
+        DCMDATA_ERROR("Failed to normalize file path: '" << filepath_in << "'");
+        return EC_InvalidFilename;
+    }
+
+    // resolve short file and directory name components such as "PROGRA~1"
+    // (which is the short 8.3 version for "Program Files") into the long names
+    res = GetLongPathNameA(buf, buf, 32768);
+    if ((res == 0) || (res > 32768))
+    {
+        DCMDATA_ERROR("Failed to normalize file path: '" << filepath_in << "'");
+        return EC_InvalidFilename;
+    }
+
+    // convert all characters to uppercase using a function that (hopefully)
+    // uses the same mapping table as the WIN32 file API
+    size_t len = strlen(buf);
+    if (len != CharUpperBuffA(buf, OFstatic_cast(DWORD, len)))
+    {
+        DCMDATA_ERROR("Failed to normalize file path: '" << filepath_in << "'");
+        return EC_InvalidFilename;
+    }
+    filepath_out = buf;
+#else
+    // resolve a relative path to an absolute path without symbolic links
+    char *resolved_path = realpath(filepath_in.c_str(), NULL);
+    if (resolved_path == NULL)
+    {
+        DCMDATA_ERROR("Failed to normalize file path: '" << filepath_in << "'");
+        return EC_InvalidFilename;
+    }
+    filepath_out = resolved_path;
+    free(resolved_path);
+#endif
+    return EC_Normal;
+}
+
+
+OFCondition DcmJSONReader::addPermittedBulkdataPath(const OFString& dirpath)
+{
+    OFString std_dirpath;
+    OFCondition result = normalizePath(dirpath, std_dirpath);
+    if ((std_dirpath.length() > 0) && (std_dirpath[std_dirpath.length()-1] != PATH_SEPARATOR))
+    {
+        std_dirpath.append(1, PATH_SEPARATOR);
+    }
+
+    if (result.good()) permittedBulkdataDirs_.push_back(std_dirpath);
+    return result;
+
+}
+
+
+OFBool DcmJSONReader::bulkdataPathPermitted(const OFString& filepath) const
+{
+    OFListConstIterator(OFString) iter = permittedBulkdataDirs_.begin();
+    OFListConstIterator(OFString) last = permittedBulkdataDirs_.end();
+    while (iter != last)
+    {
+        if (filepath.substr(0, (*iter).length()) == *iter) return OFTrue;
+        ++iter;
+    }
+    return OFFalse;
+}
+
+
+OFCondition DcmJSONReader::loadBulkdataFile(
+    DcmElement& element,
+    const OFString& filepath,
+    size_t offset,
+    size_t length)
+{
+    // open file for reading
+    OFFile file;
+    if (! file.fopen(filepath, "rb"))
+    {
+        OFString s("(unknown error code)");
+        file.getLastErrorString(s);
+        return makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str());
+    }
+
+    // obtain file size and check if file is large enough
+    const size_t filelen = OFStandard::getFileSize(filepath);
+    if (0 == length) length = filelen;
+    if (offset + length > filelen)
+    {
+        DCMDATA_ERROR("bulk data file too short: '" << filepath << "', expected " << offset + length << " bytes but only found " << filelen);
+        return EC_EndOfStream;
+    }
+
+    // allocate buffer
+    Uint8 *bulkDataBuffer = new (std::nothrow) Uint8[length];
+    if (bulkDataBuffer == NULL)
+    {
+        DCMDATA_ERROR("out of memory: failed to allocate buffer for bulk data file");
+        return EC_MemoryExhausted;
+    }
+
+    // seek to the given offset within the file
+    if (offset > 0)
+    {
+        if (0 != file.fseek(offset, SEEK_SET))
+        {
+            OFString s("(unknown error code)");
+            file.getLastErrorString(s);
+            delete[] bulkDataBuffer;
+            return makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str());
+        }
+    }
+
+    // read the bulk data into the buffer
+    size_t res = file.fread(bulkDataBuffer, 1, length);
+
+    // we ignore the fclose() return code, which is safe since the file is read-only
+    file.fclose();
+
+    // check the number of bytes read
+    if (res != length)
+    {
+        OFString s("(unknown error code)");
+        file.getLastErrorString(s);
+        delete[] bulkDataBuffer;
+        return makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str());
+    }
+
+    // file was successfully read into buffer. Store the result.
+    OFCondition result = storeBulkValue(element, bulkDataBuffer, length);
+    delete[] bulkDataBuffer;
+    return result;
+}
index 3104da27264155d3f62e67c5a1615d5c32c81e25..26332cbcd18c953a26471cfe23688147f858ce58 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2019, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -22,6 +22,7 @@
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 #include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/ofstd/oflimits.h"
 #include "dcmtk/dcmdata/dclist.h"
 
 
@@ -30,7 +31,7 @@
 // *****************************************
 
 
-DcmListNode::DcmListNode( DcmObject *obj )
+DcmListNode::DcmListNode(DcmObject *obj)
   : nextNode(NULL),
     prevNode(NULL),
     objNodeValue(obj)
@@ -51,10 +52,18 @@ DcmListNode::~DcmListNode()
 // *****************************************
 
 
+// value should be identical to DCM_EndOfListIndex, e.g. 0xffffffff for 32 bit
+static const unsigned long invalidListPosition = OFnumeric_limits<unsigned long>::max();
+
+
+// ********************************
+
+
 DcmList::DcmList()
   : firstNode(NULL),
     lastNode(NULL),
     currentNode(NULL),
+    currentPosition(invalidListPosition),
     cardinality(0)
 {
 }
@@ -65,16 +74,17 @@ DcmList::DcmList()
 
 DcmList::~DcmList()
 {
-    if ( !DcmList::empty() )                      // list is not empty !
+    if (!DcmList::empty())
     {
-        lastNode->nextNode = NULL;                // set to 0 for safety reasons
+        lastNode->nextNode = NULL;                 // set to 0 for safety reasons
         do {
             DcmListNode *temp = firstNode;
             firstNode = firstNode->nextNode;
-            // delete temp->objNodeValue;         // dangerous!
+            // delete temp->objNodeValue;          // dangerous!
             delete temp;
-        } while ( firstNode != NULL );
+        } while (firstNode != NULL);
         currentNode = firstNode = lastNode = NULL;
+        currentPosition = invalidListPosition;
     }
 }
 
@@ -82,20 +92,29 @@ DcmList::~DcmList()
 // ********************************
 
 
-DcmObject *DcmList::append( DcmObject *obj )
+DcmObject *DcmList::append(DcmObject *obj)
 {
-    if ( obj != NULL )
+    if (obj != NULL)
     {
-        if ( DcmList::empty() )                        // list is empty !
+        if (DcmList::empty())
+        {
             currentNode = firstNode = lastNode = new DcmListNode(obj);
-        else
+            currentPosition = cardinality;
+            cardinality++;
+        }
+        // check whether object can be inserted
+        else if (cardinality < DCM_EndOfListIndex)
         {
             DcmListNode *node = new DcmListNode(obj);
             lastNode->nextNode = node;
             node->prevNode = lastNode;
             currentNode = lastNode = node;
+            currentPosition = cardinality;
+            cardinality++;
+        } else {
+            DCMDATA_DEBUG("DcmList::append() cannot insert object, maximum number of entries reached");
+            obj = NULL;
         }
-        cardinality++;
     } // obj == NULL
     return obj;
 }
@@ -104,20 +123,29 @@ DcmObject *DcmList::append( DcmObject *obj )
 // ********************************
 
 
-DcmObject *DcmList::prepend( DcmObject *obj )
+DcmObject *DcmList::prepend(DcmObject *obj)
 {
-    if ( obj != NULL )
+    if (obj != NULL)
     {
-        if ( DcmList::empty() )                        // list is empty !
+        if (DcmList::empty())
+        {
             currentNode = firstNode = lastNode = new DcmListNode(obj);
-        else
+            currentPosition = 0;
+            cardinality++;
+        }
+        // check whether object can be inserted
+        else if (cardinality < DCM_EndOfListIndex)
         {
             DcmListNode *node = new DcmListNode(obj);
             node->nextNode = firstNode;
             firstNode->prevNode = node;
             currentNode = firstNode = node;
+            currentPosition = 0;
+            cardinality++;
+        } else {
+            DCMDATA_DEBUG("DcmList::prepend() cannot insert object, maximum number of entries reached");
+            obj = NULL;
         }
-        cardinality++;
     } // obj == NULL
     return obj;
 }
@@ -126,51 +154,59 @@ DcmObject *DcmList::prepend( DcmObject *obj )
 // ********************************
 
 
-DcmObject *DcmList::insert( DcmObject *obj, E_ListPos pos )
+DcmObject *DcmList::insert(DcmObject *obj, const E_ListPos pos)
 {
-    if ( obj != NULL )
+    if (obj != NULL)
     {
-        if ( DcmList::empty() )                 // list is empty !
+        if (DcmList::empty())
         {
             currentNode = firstNode = lastNode = new DcmListNode(obj);
+            currentPosition = 0;
             cardinality++;
         }
-        else {
-            if ( pos==ELP_last )
-                DcmList::append( obj );         // cardinality++;
-            else if ( pos==ELP_first )
-                DcmList::prepend( obj );        // cardinality++;
-            else if ( !DcmList::valid() )
+        // check whether object can be inserted
+        else if (cardinality < DCM_EndOfListIndex)
+        {
+            if (pos == ELP_last)                   // insert at the end
+                DcmList::append(obj);
+            else if (pos == ELP_first)             // insert at the beginning
+                DcmList::prepend(obj);
+            else if (!DcmList::valid())
                 // set current node to the end if there is no predecessor or
                 // there are successors to be determined
-                DcmList::append( obj );         // cardinality++;
-            else if ( pos == ELP_prev )         // insert before current node
+                DcmList::append(obj);
+            else if (pos == ELP_prev)              // insert before current node
             {
                 DcmListNode *node = new DcmListNode(obj);
-                if ( currentNode->prevNode == NULL )
-                    firstNode = node;           // insert at the beginning
+                if (currentNode->prevNode == NULL)
+                    firstNode = node;              // insert at the beginning
                 else
                     currentNode->prevNode->nextNode = node;
                 node->prevNode = currentNode->prevNode;
                 node->nextNode = currentNode;
                 currentNode->prevNode = node;
                 currentNode = node;
+                // NB: no need to update currentPosition
                 cardinality++;
             }
-            else //( pos==ELP_next || pos==ELP_atpos )
-                                                // insert after current node
+            else // (pos == ELP_next || pos == ELP_atpos)
+                                                   // insert after current node
             {
                 DcmListNode *node = new DcmListNode(obj);
-                if ( currentNode->nextNode == NULL )
-                    lastNode = node;            // append to the end
+                if (currentNode->nextNode == NULL)
+                    lastNode = node;               // append to the end
                 else
                     currentNode->nextNode->prevNode = node;
                 node->nextNode = currentNode->nextNode;
                 node->prevNode = currentNode;
                 currentNode->nextNode = node;
                 currentNode = node;
+                currentPosition++;
                 cardinality++;
             }
+        } else {
+            DCMDATA_DEBUG("DcmList::insert() cannot insert object, maximum number of entries reached");
+            obj = NULL;
         }
     } // obj == NULL
     return obj;
@@ -185,20 +221,20 @@ DcmObject *DcmList::remove()
     DcmObject *tempobj;
     DcmListNode *tempnode;
 
-    if ( DcmList::empty() )                        // list is empty !
+    if (DcmList::empty())
         return NULL;
-    else if ( !DcmList::valid() )
+    else if (!DcmList::valid())
         return NULL;                               // current node is 0
     else
     {
         tempnode = currentNode;
 
-        if ( currentNode->prevNode == NULL )
+        if (currentNode->prevNode == NULL)
             firstNode = currentNode->nextNode;     // delete first element
         else
             currentNode->prevNode->nextNode = currentNode->nextNode;
 
-        if ( currentNode->nextNode == NULL )
+        if (currentNode->nextNode == NULL)
             lastNode = currentNode->prevNode;      // delete last element
         else
             currentNode->nextNode->prevNode = currentNode->prevNode;
@@ -206,6 +242,7 @@ DcmObject *DcmList::remove()
         currentNode = currentNode->nextNode;
         tempobj = tempnode->value();
         delete tempnode;
+        // NB: no need to update currentPosition
         cardinality--;
         return tempobj;
     }
@@ -215,32 +252,52 @@ DcmObject *DcmList::remove()
 // ********************************
 
 
-DcmObject *DcmList::get( E_ListPos pos )
+DcmObject *DcmList::get(const E_ListPos pos)
 {
-    return seek( pos );
+    return seek(pos);
 }
 
 
 // ********************************
 
 
-DcmObject *DcmList::seek( E_ListPos pos )
+DcmObject *DcmList::seek(const E_ListPos pos)
 {
     switch (pos)
     {
-        case ELP_first :
+        case ELP_first:
             currentNode = firstNode;
+            if (DcmList::valid())
+                currentPosition = 0;
+            else
+                currentPosition = invalidListPosition;
             break;
-        case ELP_last :
+        case ELP_last:
             currentNode = lastNode;
+            if (DcmList::valid())
+                currentPosition = cardinality - 1;
+            else
+                currentPosition = invalidListPosition;
             break;
-        case ELP_prev :
-            if ( DcmList::valid() )
+        case ELP_prev:
+            if (DcmList::valid())
+            {
                 currentNode = currentNode->prevNode;
+                if (DcmList::valid())
+                    currentPosition--;
+                else
+                    currentPosition = invalidListPosition;
+            }
             break;
-        case ELP_next :
-            if ( DcmList::valid() )
+        case ELP_next:
+            if (DcmList::valid())
+            {
                 currentNode = currentNode->nextNode;
+                if (DcmList::valid())
+                    currentPosition++;
+                else
+                    currentPosition = invalidListPosition;
+            }
             break;
         default:
             break;
@@ -252,26 +309,71 @@ DcmObject *DcmList::seek( E_ListPos pos )
 // ********************************
 
 
-DcmObject *DcmList::seek_to(unsigned long absolute_position)
+DcmObject *DcmList::seek_to(const unsigned long absolute_position)
 {
+    if (absolute_position >= cardinality)
+    {
+        // invalid position
+        currentNode = NULL;
+        currentPosition = invalidListPosition;
+        return NULL;
+    }
+    else if (absolute_position == 0)
+    {
+        // first item in the list
+        return seek(ELP_first);
+    }
+    else if (absolute_position == cardinality - 1)
+    {
+        // last item in the list
+        return seek(ELP_last);
+    }
+    else if (currentPosition != invalidListPosition)
+    {
+        // determine distance between current and requested position
+        const unsigned long distance = (absolute_position >= currentPosition)
+            ? (absolute_position - currentPosition)
+            : (currentPosition - absolute_position);
+
+         // Are we seeking to a position that is closer to the current position than to
+         // the start or end of the sequence? This is often the case, if we are using
+         // seek_to() to essentially iterate over the sequence, for example. If so, then
+         // let's start iterating from the current position. Often, the position we want
+         // is simply the next position (or maybe the previous one). Let's make those
+         // use cases be O(1), and not O(n).
+        if ((distance <= absolute_position) && (distance < cardinality - absolute_position))
+        {
+            if (currentPosition <= absolute_position)
+            {
+                while (currentPosition < absolute_position)
+                    seek(ELP_next);
+            }
+            else
+            {
+                while (currentPosition > absolute_position)
+                    seek(ELP_prev);
+            }
+            return get(ELP_atpos);
+        }
+    }
+
+    // iterate from the start...
     if (absolute_position < cardinality / 2)
     {
         /* iterate over first half of the list */
-        seek( ELP_first );
+        seek(ELP_first);
         for (unsigned long i = 0; i < absolute_position; i++)
-            seek( ELP_next );
+            seek(ELP_next);
     }
-    else if (absolute_position < cardinality)
+    else // ... or the end of the list
     {
-        /* iterate over second half of the list (starting from the end) */
-        seek( ELP_last );
+        assert(absolute_position < cardinality);
+        // iterate over second half of the list (starting from the end)
+        seek(ELP_last);
         for (unsigned long i = absolute_position + 1; i < cardinality; i++)
-            seek( ELP_prev );
-    } else {
-        /* invalid position */
-        currentNode = NULL;
+            seek(ELP_prev);
     }
-    return get( ELP_atpos );
+    return get(ELP_atpos);
 }
 
 
@@ -304,5 +406,6 @@ void DcmList::deleteAllElements()
     firstNode = NULL;
     lastNode = NULL;
     currentNode = NULL;
+    currentPosition = invalidListPosition;
     cardinality = 0;
 }
index d3ce592706b7ddc9297a9a56f8f2ca0edca4266b..8ff7ffbe5bd7cb7422731215f35d17e3202282e2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -666,3 +666,10 @@ OFCondition DcmMetaInfo::loadFile(const OFFilename &fileName,
     }
     return l_error;
 }
+
+// ********************************
+
+const char *DcmMetaInfo::getPreamble() const
+{
+    return filePreamble;
+}
index c3ea92c41dca35773c62cffe419c2071a08eb96f..8aaea51c6edb717299b7ffdc93e0111ed7d1466e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2024, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,9 +26,7 @@
 #include "dcmtk/ofstd/ofconsol.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
index 4234c1369380be59bd1efce36327ecc9117fb8aa..0b56d8c88fcfc1ead187a6e37f81f0776b77da8b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2023, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,9 +26,7 @@
 #include "dcmtk/ofstd/ofconsol.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
index 50451d60ba0c334168a6844748c282bd7b905329..eddd0596e74abaf765dc9a842327cb1a0f68b0ee 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2024, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -1298,27 +1298,77 @@ OFCondition DcmPixelData::writeJson(STD_NAMESPACE ostream &out,
     // check if we have an empty uncompressed value field.
     // We never encode that as BulkDataURI.
     OFBool emptyValue = OFFalse;
-    if ((current == repListEnd) && existUnencapsulated && (getLengthField() == 0))
+    if ((current == repListEnd) && existUnencapsulated && (getLength() == 0))
     {
       emptyValue = OFTrue;
     }
 
-    // now check if the pixel data will be written as
-    // BulkDataURI, which is possible for both uncompressed
-    // and encapsulated pixel data.
-    OFString value;
-    if ((! emptyValue) && format.asBulkDataURI(getTag(), value))
+    // determine the length either of the pixel sequence or of the uncompressed pixel data
+    Uint32 len = 0;
+    if (current == repListEnd) len = getLength();
+    else if ((*current)->pixSeq != NULL) len = (*current)->pixSeq->getLength();
+
+    // check if the pixel data should be written as BulkDataURI
+    if (((! emptyValue) || (current != repListEnd)) && format.asBulkDataURI(getTag(), len))
     {
-        /* write JSON Opener */
-        writeJsonOpener(out, format);
+        // We should write the pixel data as bulk data. Now check whether
+        // we are dealing with encapsulated or unencapsulated data
+        if ((current == repListEnd) && existUnencapsulated)
+        {
+            // Current pixel data representation is unencapsulated.
+            // Write JSON Opener
+            writeJsonOpener(out, format);
 
-        /* return defined BulkDataURI */
-        format.printBulkDataURIPrefix(out);
-        DcmJsonFormat::printString(out, value);
+            // adjust byte order to little endian
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
 
-        /* write JSON Closer */
-        writeJsonCloser(out, format);
-        return EC_Normal;
+            // write as bulk data
+            OFCondition status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
+
+            // write JSON Closer
+            writeJsonCloser(out, format);
+            return status;
+        }
+        else if (current != repListEnd)
+        {
+            // Current pixel data representation is encapsulated.
+            // Access the parent item to check the number of frames
+            DcmItem *parentItem = getParentItem();
+            if (parentItem == NULL)
+            {
+                // something is fishy with this dataset
+                DCMDATA_WARN("DcmPixelData: Unable to access parent dataset for pixel data object");
+                return EC_CannotWriteBulkDataFile;
+            }
+
+            // check NumberOfFrames attribute, default to 1 if absent or unreadable
+            Sint32 imageFrames = 1;
+            if (parentItem->findAndGetSint32(DCM_NumberOfFrames, imageFrames).bad()) imageFrames = 1;
+            if (imageFrames != 1)
+            {
+                DCMDATA_WARN("Encapsulated multi-frame images cannot be represented in JSON");
+                return EC_CannotWriteJSONMultiframe;
+            }
+
+            // (*current)->pixSeq is not NULL at this point, we have checked this earlier in this method
+            DcmPixelSequence *currentPixelSequence = (*current)->pixSeq;
+
+            // write JSON Opener
+            writeJsonOpener(out, format);
+
+            // delegate the JSON conversion to the pixel sequence
+            OFCondition status = currentPixelSequence->writeJson(out, format);
+
+            // write JSON Closer
+            writeJsonCloser(out, format);
+            return status;
+        }
+        else
+        {
+            // something is fishy with this dataset
+            DCMDATA_WARN("DcmPixelData: apparently there is neither compressed nor uncompressed data");
+            return EC_CannotWriteJsonInlineBinary;
+        }
     }
 
     // No bulk data URI, we're supposed to write as InlineBinary.
@@ -1356,3 +1406,21 @@ OFCondition DcmPixelData::writeJson(STD_NAMESPACE ostream &out,
     // pixel data is encapsulated, return error
     return EC_CannotWriteJsonInlineBinary;
 }
+
+
+Uint16 DcmPixelData::decodedBitsAllocated(
+      Uint16 bitsAllocated,
+      Uint16 bitsStored) const
+{
+    if (bitsStored > bitsAllocated) return 0;
+    if (existUnencapsulated || (original == repListEnd))
+    {
+        // we have uncompressed pixel data or pixel data is empty
+        return DcmElement::decodedBitsAllocated(bitsAllocated, bitsStored);
+    }
+    else
+    {
+       return DcmCodecList::decodedBitsAllocated((*original)->repType, bitsAllocated, bitsStored);
+    }
+}
+
index 7d81fb68033a5686d311a4235cb32200b36d3f3d..2cf95c13909ce89ff97e8f57e6626acac955e13d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/ofstd/ofstream.h"
 #include "dcmtk/ofstd/ofuuid.h"
+#include "dcmtk/ofstd/ofsha256.h"
 
 #include "dcmtk/dcmdata/dcpixseq.h"
 #include "dcmtk/dcmdata/dcpxitem.h"
 #include "dcmtk/dcmdata/dcitem.h"
 #include "dcmtk/dcmdata/dcvr.h"
-
 #include "dcmtk/dcmdata/dcdeftag.h"
-
+#include "dcmtk/dcmdata/dcjson.h"
 
 // ********************************
 
@@ -181,6 +181,100 @@ OFCondition DcmPixelSequence::writeXML(STD_NAMESPACE ostream &out,
     return l_error;
 }
 
+// ********************************
+
+OFCondition DcmPixelSequence::writeJson(
+    STD_NAMESPACE ostream &out,
+    DcmJsonFormat &format)
+{
+    // At this point, we can safely assume that this is a single frame image
+    // since this has been checked in DcmPixelData::writeJson().
+
+    OFCondition status = EC_Normal;
+    unsigned long numItems = card();
+    if (numItems < 2)
+    {
+        DCMDATA_WARN("DcmPixelSequence: pixel sequence is empty");
+        return EC_CannotWriteBulkDataFile;
+    }
+
+    // compute SHA-2 checksum over all pixel data fragments,
+    // not including the basic offset table (i.e. the first item)
+    OFSHA256 sha256;
+    Uint8 hash[32];
+    DcmPixelItem *pixItem = NULL;
+    Uint8 *pixelData = NULL;
+    Uint32 fragmentLength = 0;
+    for (unsigned long i = 1; i < numItems; ++i)
+    {
+        status = getItem(pixItem, i);
+        if (status.bad()) return status;
+        fragmentLength = pixItem->getLength();
+        status = pixItem->getUint8Array(pixelData);
+        if (status.bad()) return status;
+        sha256.update(pixelData, fragmentLength);
+    }
+    sha256.final(hash);
+
+    // determine filename and path
+    DcmXfer xfer(Xfer);
+    OFString bulkname;
+    char hashstring[3];
+    for (int i=0; i < 32; ++i)
+    {
+        OFStandard::snprintf(hashstring, sizeof(hashstring), "%02x", hash[i]);
+        bulkname.append(hashstring);
+    }
+    bulkname.append(xfer.getFilenameExtension());
+
+    OFString bulkpath;
+    format.getBulkDataDirectory(bulkpath);
+    bulkpath.append(bulkname);
+
+    /* check if file already exists. In this case, the file content is the same
+     * we would create now since the SHA-256 checksum is the same. So we can just
+     * use the existing file.
+     */
+    if (! OFStandard::fileExists(bulkpath))
+    {
+        OFFile bulkfile;
+        if (! bulkfile.fopen(bulkpath.c_str(), "wb"))
+        {
+            DCMDATA_ERROR("Unable to create bulk data file '" << bulkpath << "'");
+            return EC_CannotWriteBulkDataFile;
+        }
+
+        // write all fragments into a single file, as specified in DICOM part 18, section 8.7.3.3.2.
+        for (unsigned long i = 1; i < numItems; ++i)
+        {
+            status = getItem(pixItem, i);
+            if (status.bad()) return status;
+            fragmentLength = pixItem->getLength();
+            status = pixItem->getUint8Array(pixelData);
+            if (status.bad()) return status;
+            if (fragmentLength != bulkfile.fwrite(pixelData, 1, fragmentLength))
+            {
+                DCMDATA_ERROR("Unable to write bulk data to file '" << bulkpath << "'");
+                return EC_CannotWriteBulkDataFile;
+            }
+        }
+
+        if (bulkfile.fclose())
+        {
+            DCMDATA_ERROR("Unable to close bulk data file '" << bulkpath << "'");
+            return EC_CannotWriteBulkDataFile;
+        }
+    }
+
+    // print BulkDataURI (the enclosing Json opener and closer are printed in class DcmPixelData)
+    format.printBulkDataURIPrefix(out);
+    OFString bulkDataURI;
+    format.getBulkDataURIPrefix(bulkDataURI);
+    bulkDataURI.append(bulkname);
+    DcmJsonFormat::printString(out, bulkDataURI);
+    return status;
+}
+
 
 // ********************************
 
index fd01b63ba22704ece0d1228c238ca1b8220bca78..6e284f78ae8b5d93daf9c3366e7c37d1cd1aea68 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2024, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -60,6 +60,20 @@ OFBool DcmRLECodecDecoder::canChangeCoding(
 }
 
 
+Uint16 DcmRLECodecDecoder::decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 /* bitsStored */) const
+{
+    // The RLE decoder only supports images where BitsAllocated is a multiple of 8.
+    if ((bitsAllocated < 8)||(bitsAllocated % 8 != 0)) return 0;
+
+    // RLE cannot support more than 120 bits/sample (15 bands) in DICOM
+    if (bitsAllocated > 120) return 0;
+
+    return bitsAllocated;
+}
+
+
 OFCondition DcmRLECodecDecoder::decode(
     const DcmRepresentationParameter * /* fromRepParam */,
     DcmPixelSequence * pixSeq,
@@ -298,7 +312,7 @@ OFCondition DcmRLECodecDecoder::decode(
                     {
                       if (rledecoder.size() < bytesPerStripe)
                       {
-                        DCMDATA_WARN("RLE decoder is finished but has produced insufficient data for this stripe, will continue with next pixel item");
+                        DCMDATA_WARN("DcmRLECodecDecoder: Detected fragmented RLE compressed pixel data, which is not allowed in DICOM");
                         DCMDATA_DEBUG("RLE decoder processes pixel item " << currentItem);
                         result = pixSeq->getItem(pixItem, currentItem++);
                         if (result.good())
@@ -334,6 +348,7 @@ OFCondition DcmRLECodecDecoder::decode(
 
                       if (result.good() || result == EC_StreamNotifyClient)
                       {
+                        DCMDATA_WARN("DcmRLECodecDecoder: Detected fragmented RLE compressed pixel data, which is not allowed in DICOM");
                         DCMDATA_DEBUG("RLE decoder processes pixel item " << currentItem);
                         result = pixSeq->getItem(pixItem, currentItem++);
                       }
@@ -348,6 +363,12 @@ OFCondition DcmRLECodecDecoder::decode(
                     } /* while */
 
                     // last fragment for this RLE stripe
+                    if (inputBytes + byteOffset > fragmentLength)
+                    {
+                        DCMDATA_WARN("DcmRLECodecDecoder: Stream size in RLE header is wrong, adjusting from " << inputBytes << " to " << fragmentLength-byteOffset << " bytes");
+                        inputBytes = fragmentLength-byteOffset;
+                    }
+
                     result = rledecoder.decompress(rleData + byteOffset, OFstatic_cast(size_t, inputBytes));
 
                     // special handling for zero pad byte at the end of the RLE stream
@@ -366,7 +387,7 @@ OFCondition DcmRLECodecDecoder::decode(
                 if (lastStripeOfColor && (rledecoder.size() < bytesPerStripe))
                 {
                     // stripe ended prematurely? report a warning and continue
-                    DCMDATA_WARN("RLE decoder is finished but has produced insufficient data for this stripe, filling remaining pixels");
+                    DCMDATA_WARN("DcmRLECodecDecoder: RLE decoder is finished but has produced insufficient data for this stripe, filling remaining pixels");
                     result = EC_Normal;
                 }
                 else if (rledecoder.size() != bytesPerStripe)
@@ -617,6 +638,11 @@ OFCondition DcmRLECodecDecoder::decodeFrame(
             // if the RLE data is split in multiple fragments. We need to feed
             // data fragment by fragment until the RLE codec has produced
             // sufficient output.
+            if (fragmentLength < byteOffset)
+            {
+              DCMDATA_ERROR("Byte offset in RLE header is wrong.");
+              return EC_CannotChangeRepresentation;
+            }
             bytesToDecode = OFstatic_cast(size_t, fragmentLength - byteOffset);
         }
         else
@@ -724,6 +750,10 @@ OFCondition DcmRLECodecDecoder::decodeFrame(
     }
 
     // adjust byte order for uncompressed image to little endian
+    if ((gLocalByteOrder == EBO_BigEndian) && (frameSize & 1))
+    {
+      DCMDATA_WARN("Size of frame buffer is odd, cannot correct byte order for last pixel value");
+    }
     swapIfNecessary(EBO_LittleEndian, gLocalByteOrder, imageData16, frameSize, sizeof(Uint16));
 
     return result;
index ef835f4edda818f9fa9310a44a94017646276b09..f8ba1f73db539c38ef8d23ef1b385eb8f981aa9c 100644 (file)
@@ -62,6 +62,14 @@ OFBool DcmRLECodecEncoder::canChangeCoding(
 }
 
 
+Uint16 DcmRLECodecEncoder::decodedBitsAllocated(
+    Uint16 /* bitsAllocated */,
+    Uint16 /* bitsStored */) const
+{
+  return 0;
+}
+
+
 OFCondition DcmRLECodecEncoder::decode(
     const DcmRepresentationParameter * /* fromRepParam */,
     DcmPixelSequence * /* pixSeq */,
index c4f0ec29395d13e64cf4ec6f4cff2a353bce608a..9f5481661335e2435dbb5c4535e02157292c5690 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2024, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -175,12 +175,12 @@ OFCondition DcmSpecificCharacterSet::selectCharacterSet(const OFString &fromChar
         if (sourceVM == 0)
         {
             // no character set specified, use ASCII
-            status = DefaultEncodingConverter.selectEncoding("ASCII", DestinationEncoding);
+            status = DefaultEncodingConverter.selectEncoding("ASCII", getDestinationEncoding());
             // output some useful debug information
             if (status.good())
             {
                 DCMDATA_DEBUG("DcmSpecificCharacterSet: Selected character set '' (ASCII) "
-                    << "for the conversion to " << DestinationEncoding);
+                    << "for the conversion to " << getDestinationEncoding());
             }
         }
         else if (sourceVM == 1)
@@ -327,12 +327,12 @@ OFCondition DcmSpecificCharacterSet::selectCharacterSetWithoutCodeExtensions()
     // check whether an appropriate character encoding has been found
     if (!fromEncoding.empty())
     {
-        status = DefaultEncodingConverter.selectEncoding(fromEncoding, DestinationEncoding);
+        status = DefaultEncodingConverter.selectEncoding(fromEncoding, getDestinationEncoding());
         // output some useful debug information
         if (status.good())
         {
             DCMDATA_DEBUG("DcmSpecificCharacterSet: Selected character set '" << SourceCharacterSet
-                << "' (" << fromEncoding << ") for the conversion to " << DestinationEncoding);
+                << "' (" << fromEncoding << ") for the conversion to " << getDestinationEncoding());
         }
     }
     return status;
@@ -469,12 +469,12 @@ OFCondition DcmSpecificCharacterSet::selectCharacterSetWithCodeExtensions(const
             // but first check whether this encoding has already been added before
             if (conv.second)
             {
-                status = conv.first->second.selectEncoding(encodingName, DestinationEncoding);
+                status = conv.first->second.selectEncoding(encodingName, getDestinationEncoding());
                 if (status.good())
                 {
                     // output some useful debug information
                     DCMDATA_DEBUG("DcmSpecificCharacterSet: Added character set '" << definedTerm
-                        << "' (" << encodingName << ") for the conversion to " << DestinationEncoding);
+                        << "' (" << encodingName << ") for the conversion to " << getDestinationEncoding());
                     // also remember the default descriptor, which refers to the first character set
                     if (i == 0)
                     {
@@ -502,12 +502,12 @@ OFCondition DcmSpecificCharacterSet::selectCharacterSetWithCodeExtensions(const
             OFMake_pair(OFString("ISO 2022 IR 6"), OFCharacterEncoding()));
         if (conv.second)
         {
-            status = conv.first->second.selectEncoding("ASCII", DestinationEncoding);
+            status = conv.first->second.selectEncoding("ASCII", getDestinationEncoding());
             if (status.good())
             {
                 // output some useful debug information
                 DCMDATA_DEBUG("DcmSpecificCharacterSet: Added character set 'ISO 2022 IR 6' (ASCII) "
-                    << "for the conversion to " << DestinationEncoding
+                    << "for the conversion to " << getDestinationEncoding()
                     << " (because it is needed for one or more of the previously added character sets)");
             } else {
                 DCMDATA_ERROR("DcmSpecificCharacterSet: 'ISO 2022 IR 6' is not supported by"
@@ -540,108 +540,61 @@ OFCondition DcmSpecificCharacterSet::convertString(const char *fromString,
     const OFBool hasEscapeChar = checkForEscapeCharacter(fromString, fromLength);
     if (EncodingConverters.empty() || (!hasEscapeChar && delimiters.empty()))
     {
-        if (delimiters.empty())
+        // convert string without code extensions according to ISO 2022
+        status = convertStringWithoutCodeExtensions(fromString, fromLength, toString, delimiters);
+    } else {
+        // convert string with code extensions according to ISO 2022
+        status = convertStringWithCodeExtensions(fromString, fromLength, toString, delimiters, hasEscapeChar);
+    }
+    if (status.good())
+    {
+        // finally, output some debug information
+        if (getDestinationEncoding() == "UTF-8")
         {
-            // no code extensions according to ISO 2022 used and no delimiters - this is the simple case
-            DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
-                << convertToLengthLimitedOctalString(fromString, fromLength) << "'");
-            status = DefaultEncodingConverter.convertString(fromString, fromLength, toString, OFTrue /*clearMode*/);
+            // output code points only in case of UTF-8 output
+            DCMDATA_TRACE("Converted result in " << getDestinationEncoding() << " is '"
+                << convertToLengthLimitedOctalString(toString.c_str(), toString.length()) << "' ("
+                << countCharactersInUTF8String(toString) << " code points)");
         } else {
-            // no code extensions according to ISO 2022 used, but delimiters
-            DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
-                << convertToLengthLimitedOctalString(fromString, fromLength)
-                << "' (with delimiters '" << delimiters << "')");
-
-            toString.clear();
-            size_t pos = 0;
-            const char *firstChar = fromString;
-            const char *currentChar = fromString;
-
-            // iterate over all characters of the string (as long as there is no error)
-            while ((pos < fromLength) && status.good())
-            {
-                const char c0 = *currentChar++;
+            DCMDATA_TRACE("Converted result in " << getDestinationEncoding() << " is '"
+                << convertToLengthLimitedOctalString(toString.c_str(), toString.length()) << "'");
+        }
+    }
+    return status;
+}
 
-                // check for characters ESC, HT, LF, FF, CR or any other specified delimiter
-                if ((c0 == '\011') || (c0 == '\012') || (c0 == '\014') || (c0 == '\015') || (delimiters.find(c0) != OFString_npos))
-                {
-                    // convert the sub-string (before the delimiter) with the current character set
-                    const size_t convertLength = currentChar - firstChar - 1;
-                    if (convertLength > 0)
-                    {
-                        // output some debug information
-                        DCMDATA_TRACE("    Converting sub-string '"
-                            << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
-                        status = DefaultEncodingConverter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
-                        if (status.bad())
-                            DCMDATA_TRACE("    -> ERROR: " << status.text());
-                    }
 
-                    // output some debug information
-                    DCMDATA_TRACE("    Appending delimiter '"
-                        << convertToLengthLimitedOctalString(currentChar - 1 /* identical to c0 */, 1)
-                        << "' to the output");
-                    // don't forget to append the delimiter
-                    toString += c0;
-
-                    // start new sub-string after delimiter
-                    firstChar = currentChar;
-                }
-                ++pos;
-            }
-            if (status.good())
-            {
-                // convert any remaining characters from the input string
-                const size_t convertLength = currentChar - firstChar;
-                if (convertLength > 0)
-                {
-                    // output some debug information
-                    DCMDATA_TRACE("    Converting remaining sub-string '"
-                        << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
-                    status = DefaultEncodingConverter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
-                    if (status.bad())
-                        DCMDATA_TRACE("    -> ERROR: " << status.text());
-                }
-            }
-        }
+OFCondition DcmSpecificCharacterSet::convertStringWithoutCodeExtensions(const char *fromString,
+                                                                        const size_t fromLength,
+                                                                        OFString &toString,
+                                                                        const OFString &delimiters)
+{
+    OFCondition status = EC_Normal;
+    // any delimiters defined?
+    if (delimiters.empty())
+    {
+        // case 1: no code extensions used and no delimiters defined - this is the simple case
+        DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
+            << convertToLengthLimitedOctalString(fromString, fromLength) << "'");
+        status = DefaultEncodingConverter.convertString(fromString, fromLength, toString, OFTrue /*clearMode*/);
     } else {
-        if (delimiters.empty())
-        {
-            DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
-                << convertToLengthLimitedOctalString(fromString, fromLength)
-                << "' (with code extensions)");
-        } else {
-            DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
-                << convertToLengthLimitedOctalString(fromString, fromLength)
-                << "' (with " << (hasEscapeChar ? "code extensions and " : "")
-                << "delimiters '" << delimiters << "')");
-        }
-        // code extensions according to ISO 2022 (possibly) used, so we need to check
-        // for particular escape sequences in order to switch between character sets
+        // case 2: no code extensions used, but delimiters defined
+        DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
+            << convertToLengthLimitedOctalString(fromString, fromLength)
+            << "' (with delimiters '" << delimiters << "')");
+
         toString.clear();
         size_t pos = 0;
-        // some (extended) character sets use more than 1 byte per character
-        // (however, the default character set always uses a single byte)
-        unsigned char bytesPerChar = 1;
-        // check whether '=' is a delimiter, as it is used in PN values
-        OFBool isFirstGroup = (delimiters.find('=') != OFString_npos);
-        // by default, we expect that delimiters can be checked by their corresponding ASCII codes
-        // (this implies that the default character set is not "ISO 2022 IR 87" or "ISO 2022 IR 159")
-        OFBool checkDelimiters = OFTrue;
         const char *firstChar = fromString;
         const char *currentChar = fromString;
-        // initially, use the default descriptor
-        OFCharacterEncoding converter = DefaultEncodingConverter;
-        DCMDATA_TRACE("  Starting with the default character set");
         // iterate over all characters of the string (as long as there is no error)
         while ((pos < fromLength) && status.good())
         {
             const char c0 = *currentChar++;
-            // check for characters ESC, HT, LF, FF, CR or any other specified delimiter
-            const OFBool isEscape = (c0 == '\033');
-            const OFBool isDelimiter = checkDelimiters &&
-                ((c0 == '\011') || (c0 == '\012') || (c0 == '\014') || (c0 == '\015') || (delimiters.find(c0) != OFString_npos));
-            if (isEscape || isDelimiter)
+            // check for characters HT, LF, FF, CR or any other specified delimiter
+            const OFBool isDelimiter =  ((c0 == '\011') || (c0 == '\012') || (c0 == '\014') || (c0 == '\015') ||
+                (delimiters.find(c0) != OFString_npos));
+            if (isDelimiter)
             {
                 // convert the sub-string (before the delimiter) with the current character set
                 const size_t convertLength = currentChar - firstChar - 1;
@@ -650,178 +603,19 @@ OFCondition DcmSpecificCharacterSet::convertString(const char *fromString,
                     // output some debug information
                     DCMDATA_TRACE("    Converting sub-string '"
                         << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
-                    status = converter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
+                    status = DefaultEncodingConverter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
                     if (status.bad())
                         DCMDATA_TRACE("    -> ERROR: " << status.text());
                 }
-                // check whether this was the first component group of a PN value
-                if (isDelimiter && (c0 == '='))
-                    isFirstGroup = OFFalse;
-            }
-            // the ESC character is used to explicitly switch between character sets
-            if (isEscape)
-            {
-                // report a warning as this is a violation of DICOM PS 3.5 Section 6.2.1
-                if (isFirstGroup)
-                {
-                    DCMDATA_WARN("DcmSpecificCharacterSet: Escape sequences shall not be used "
-                        << "in the first component group of a Person Name (PN), using them anyway");
-                }
-                // we need at least two more characters to determine the new character set
-                size_t escLength = 2;
-                if (pos + escLength < fromLength)
-                {
-                    OFString key;
-                    const char c1 = *currentChar++;
-                    const char c2 = *currentChar++;
-                    char c3 = '\0';
-                    if ((c1 == 0x28) && (c2 == 0x42))       // ASCII
-                        key = "ISO 2022 IR 6";
-                    else if ((c1 == 0x2d) && (c2 == 0x41))  // Latin alphabet No. 1
-                        key = "ISO 2022 IR 100";
-                    else if ((c1 == 0x2d) && (c2 == 0x42))  // Latin alphabet No. 2
-                        key = "ISO 2022 IR 101";
-                    else if ((c1 == 0x2d) && (c2 == 0x43))  // Latin alphabet No. 3
-                        key = "ISO 2022 IR 109";
-                    else if ((c1 == 0x2d) && (c2 == 0x44))  // Latin alphabet No. 4
-                        key = "ISO 2022 IR 110";
-                    else if ((c1 == 0x2d) && (c2 == 0x4c))  // Cyrillic
-                        key = "ISO 2022 IR 144";
-                    else if ((c1 == 0x2d) && (c2 == 0x47))  // Arabic
-                        key = "ISO 2022 IR 127";
-                    else if ((c1 == 0x2d) && (c2 == 0x46))  // Greek
-                        key = "ISO 2022 IR 126";
-                    else if ((c1 == 0x2d) && (c2 == 0x48))  // Hebrew
-                        key = "ISO 2022 IR 138";
-                    else if ((c1 == 0x2d) && (c2 == 0x4d))  // Latin alphabet No. 5
-                        key = "ISO 2022 IR 148";
-                    else if ((c1 == 0x2d) && (c2 == 0x62))  // Latin alphabet No. 9
-                        key = "ISO 2022 IR 203";
-                    else if ((c1 == 0x29) && (c2 == 0x49))  // Japanese, JIS X0201, G1 set (Katakana)
-                        key = "ISO 2022 IR 13";
-                    else if ((c1 == 0x28) && (c2 == 0x4a))  // Japanese, JIS X0201, G0 set (Romaji, i.e. ASCII)
-                        key = "ISO 2022 IR 13";
-                    else if ((c1 == 0x2d) && (c2 == 0x54))  // Thai
-                        key = "ISO 2022 IR 166";
-                    else if ((c1 == 0x24) && (c2 == 0x42))  // Japanese (multi-byte), JIS X0208 (Kanji)
-                        key = "ISO 2022 IR 87";
-                    else if ((c1 == 0x24) && (c2 == 0x28))  // Japanese (multi-byte), JIS X0212 (Supplementary Kanji set)
-                    {
-                        escLength = 3;
-                        // do we still have another character in the string?
-                        if (pos + escLength < fromLength)
-                        {
-                            c3 = *currentChar++;
-                            if (c3 == 0x44)
-                                key = "ISO 2022 IR 159";
-                        }
-                    }
-                    else if ((c1 == 0x24) && (c2 == 0x29)) // might be Korean or Chinese
-                    {
-                        escLength = 3;
-                        // do we still have another character in the string?
-                        if (pos + escLength < fromLength)
-                        {
-                            c3 = *currentChar++;
-                            if (c3 == 0x43)                // Korean (single- and multi-byte)
-                                key = "ISO 2022 IR 149";
-                            else if (c3 == 0x41)           // Simplified Chinese (multi-byte)
-                                key = "ISO 2022 IR 58";
-                        }
-                    }
-                    // check whether a valid escape sequence has been found
-                    if (key.empty())
-                    {
-                        OFOStringStream stream;
-                        stream << "Cannot convert character set: Illegal escape sequence 'ESC "
-                            << STD_NAMESPACE dec << STD_NAMESPACE setfill('0')
-                            << STD_NAMESPACE setw(2) << OFstatic_cast(int, c1 >> 4) << "/"
-                            << STD_NAMESPACE setw(2) << OFstatic_cast(int, c1 & 0x0f) << " "
-                            << STD_NAMESPACE setw(2) << OFstatic_cast(int, c2 >> 4) << "/"
-                            << STD_NAMESPACE setw(2) << OFstatic_cast(int, c2 & 0x0f);
-                        if (escLength == 3)
-                        {
-                            stream << " " << STD_NAMESPACE setw(2) << OFstatic_cast(int, c3 >> 4) << "/"
-                                << STD_NAMESPACE setw(2) << OFstatic_cast(int, c3 & 0x0f);
-                        }
-                        stream  << "' found" << OFStringStream_ends;
-                        OFSTRINGSTREAM_GETOFSTRING(stream, message)
-                        status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
-                    }
-                    if (status.good())
-                    {
-                        DCMDATA_TRACE("  Switching to character set '" << key << "'");
-                        T_EncodingConvertersMap::const_iterator it = EncodingConverters.find(key);
-                        // check whether the descriptor was found in the map, i.e. properly declared in (0008,0005)
-                        if (it != EncodingConverters.end())
-                        {
-                            converter = it->second;
-                            // special case: these Japanese character sets replace the ASCII part (G0 code area),
-                            // so according to DICOM PS 3.5 Section 6.2.1.2 an explicit switch to the default is required
-                            checkDelimiters = (key != "ISO 2022 IR 87") && (key != "ISO 2022 IR 159");
-                            // determine number of bytes per character (used by the selected character set)
-                            if ((key == "ISO 2022 IR 87") || (key == "ISO 2022 IR 159") || (key == "ISO 2022 IR 58"))
-                            {
-                                DCMDATA_TRACE("    Now using 2 bytes per character");
-                                bytesPerChar = 2;
-                            }
-                            else if (key == "ISO 2022 IR 149")
-                            {
-                                DCMDATA_TRACE("    Now using 1 or 2 bytes per character");
-                                bytesPerChar = 0;      // special handling for single- and multi-byte
-                            } else {
-                                DCMDATA_TRACE("    Now using 1 byte per character");
-                                bytesPerChar = 1;
-                            }
-                        } else {
-                            OFOStringStream stream;
-                            stream << "Cannot convert character set: Escape sequence refers to character set '" << key << "' that "
-                                "was not declared in SpecificCharacterSet (0008,0005)" << OFStringStream_ends;
-                            OFSTRINGSTREAM_GETOFSTRING(stream, message)
-                            status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
-                        }
-                    }
-                    pos += escLength;
-                }
-                // check whether the escape sequence was complete
-                if (status.good() && (pos >= fromLength))
-                {
-                    OFOStringStream stream;
-                    stream << "Cannot convert character set: Incomplete escape sequence (" << (escLength + 1)
-                        << " bytes expected) at the end of the string to be converted" << OFStringStream_ends;
-                    OFSTRINGSTREAM_GETOFSTRING(stream, message)
-                    status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
-                }
-                // do not copy the escape sequence to the output
-                firstChar = currentChar;
-            }
-            // the HT, LF, FF, CR character or other delimiters (depending on the VR) also cause a switch
-            else if (isDelimiter)
-            {
                 // output some debug information
                 DCMDATA_TRACE("    Appending delimiter '"
                     << convertToLengthLimitedOctalString(currentChar - 1 /* identical to c0 */, 1)
                     << "' to the output");
                 // don't forget to append the delimiter
                 toString += c0;
-                // use the default descriptor again (see DICOM PS 3.5)
-                if (converter != DefaultEncodingConverter)
-                {
-                    DCMDATA_TRACE("  Switching back to the default character set (because a delimiter was found)");
-                    converter = DefaultEncodingConverter;
-                    checkDelimiters = OFTrue;
-                }
                 // start new sub-string after delimiter
                 firstChar = currentChar;
             }
-            // skip remaining bytes of current character (if any)
-            else if (bytesPerChar != 1)
-            {
-                const size_t skipBytes = (bytesPerChar > 0) ? (bytesPerChar - 1) : ((c0 & 0x80) ? 1 : 0);
-                if (pos + skipBytes < fromLength)
-                    currentChar += skipBytes;
-                pos += skipBytes;
-            }
             ++pos;
         }
         if (status.good())
@@ -833,42 +627,263 @@ OFCondition DcmSpecificCharacterSet::convertString(const char *fromString,
                 // output some debug information
                 DCMDATA_TRACE("    Converting remaining sub-string '"
                     << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
+                status = DefaultEncodingConverter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
+                if (status.bad())
+                    DCMDATA_TRACE("    -> ERROR: " << status.text());
+            }
+        }
+    }
+    return status;
+}
+
+
+OFCondition DcmSpecificCharacterSet::convertStringWithCodeExtensions(const char *fromString,
+                                                                     const size_t fromLength,
+                                                                     OFString &toString,
+                                                                     const OFString &delimiters,
+                                                                     const OFBool hasEscapeChar)
+{
+    OFCondition status = EC_Normal;
+    // any delimiters defined?
+    if (delimiters.empty())
+    {
+        // case 3: code extensions used, but no delimiters defined
+        DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
+            << convertToLengthLimitedOctalString(fromString, fromLength)
+            << "' (with code extensions)");
+    } else {
+        // case 4: code extensions used and delimiters defined
+        DCMDATA_DEBUG("DcmSpecificCharacterSet: Converting '"
+            << convertToLengthLimitedOctalString(fromString, fromLength)
+            << "' (with " << (hasEscapeChar ? "code extensions and " : "")
+            << "delimiters '" << delimiters << "')");
+    }
+    // code extensions according to ISO 2022 (possibly) used, so we need to check
+    // for particular escape sequences in order to switch between character sets
+    toString.clear();
+    size_t pos = 0;
+    // some (extended) character sets use more than 1 byte per character
+    // (however, the default character set always uses a single byte)
+    unsigned char bytesPerChar = 1;
+    // check whether '=' is a delimiter, as it is used in PN values
+    OFBool isFirstGroup = (delimiters.find('=') != OFString_npos);
+    // by default, we expect that delimiters can be checked by their corresponding ASCII codes
+    // (this implies that the default character set is not "ISO 2022 IR 87" or "ISO 2022 IR 159")
+    OFBool checkDelimiters = OFTrue;
+    const char *firstChar = fromString;
+    const char *currentChar = fromString;
+    // initially, use the default descriptor
+    OFCharacterEncoding converter = DefaultEncodingConverter;
+    DCMDATA_TRACE("  Starting with the default character set");
+    // iterate over all characters of the string (as long as there is no error)
+    while ((pos < fromLength) && status.good())
+    {
+        const char c0 = *currentChar++;
+        // check for characters ESC, HT, LF, FF, CR or any other specified delimiter
+        const OFBool isEscape = (c0 == '\033');
+        const OFBool isDelimiter = checkDelimiters &&
+            ((c0 == '\011') || (c0 == '\012') || (c0 == '\014') || (c0 == '\015') || (delimiters.find(c0) != OFString_npos));
+        if (isEscape || isDelimiter)
+        {
+            // convert the sub-string (before the delimiter) with the current character set
+            const size_t convertLength = currentChar - firstChar - 1;
+            if (convertLength > 0)
+            {
+                // output some debug information
+                DCMDATA_TRACE("    Converting sub-string '"
+                    << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
                 status = converter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
                 if (status.bad())
                     DCMDATA_TRACE("    -> ERROR: " << status.text());
             }
+            // check whether this was the first component group of a PN value
+            if (isDelimiter && (c0 == '='))
+                isFirstGroup = OFFalse;
         }
+        // the ESC character is used to explicitly switch between character sets
+        if (isEscape)
+        {
+            // report a warning as this is a violation of DICOM PS 3.5 Section 6.2.1
+            if (isFirstGroup)
+            {
+                DCMDATA_WARN("DcmSpecificCharacterSet: Escape sequences shall not be used "
+                    << "in the first component group of a Person Name (PN), using them anyway");
+            }
+            // we need at least two more characters to determine the new character set
+            size_t escLength = 2;
+            if (pos + escLength < fromLength)
+            {
+                OFString key;
+                const char c1 = *currentChar++;
+                const char c2 = *currentChar++;
+                char c3 = '\0';
+                if ((c1 == 0x28) && (c2 == 0x42))       // ASCII
+                    key = "ISO 2022 IR 6";
+                else if ((c1 == 0x2d) && (c2 == 0x41))  // Latin alphabet No. 1
+                    key = "ISO 2022 IR 100";
+                else if ((c1 == 0x2d) && (c2 == 0x42))  // Latin alphabet No. 2
+                    key = "ISO 2022 IR 101";
+                else if ((c1 == 0x2d) && (c2 == 0x43))  // Latin alphabet No. 3
+                    key = "ISO 2022 IR 109";
+                else if ((c1 == 0x2d) && (c2 == 0x44))  // Latin alphabet No. 4
+                    key = "ISO 2022 IR 110";
+                else if ((c1 == 0x2d) && (c2 == 0x4c))  // Cyrillic
+                    key = "ISO 2022 IR 144";
+                else if ((c1 == 0x2d) && (c2 == 0x47))  // Arabic
+                    key = "ISO 2022 IR 127";
+                else if ((c1 == 0x2d) && (c2 == 0x46))  // Greek
+                    key = "ISO 2022 IR 126";
+                else if ((c1 == 0x2d) && (c2 == 0x48))  // Hebrew
+                    key = "ISO 2022 IR 138";
+                else if ((c1 == 0x2d) && (c2 == 0x4d))  // Latin alphabet No. 5
+                    key = "ISO 2022 IR 148";
+                else if ((c1 == 0x2d) && (c2 == 0x62))  // Latin alphabet No. 9
+                    key = "ISO 2022 IR 203";
+                else if ((c1 == 0x29) && (c2 == 0x49))  // Japanese, JIS X0201, G1 set (Katakana)
+                    key = "ISO 2022 IR 13";
+                else if ((c1 == 0x28) && (c2 == 0x4a))  // Japanese, JIS X0201, G0 set (Romaji, i.e. ASCII)
+                    key = "ISO 2022 IR 13";
+                else if ((c1 == 0x2d) && (c2 == 0x54))  // Thai
+                    key = "ISO 2022 IR 166";
+                else if ((c1 == 0x24) && (c2 == 0x42))  // Japanese (multi-byte), JIS X0208 (Kanji)
+                    key = "ISO 2022 IR 87";
+                else if ((c1 == 0x24) && (c2 == 0x28))  // Japanese (multi-byte), JIS X0212 (Supplementary Kanji set)
+                {
+                    escLength = 3;
+                    // do we still have another character in the string?
+                    if (pos + escLength < fromLength)
+                    {
+                        c3 = *currentChar++;
+                        if (c3 == 0x44)
+                            key = "ISO 2022 IR 159";
+                    }
+                }
+                else if ((c1 == 0x24) && (c2 == 0x29)) // might be Korean or Chinese
+                {
+                    escLength = 3;
+                    // do we still have another character in the string?
+                    if (pos + escLength < fromLength)
+                    {
+                        c3 = *currentChar++;
+                        if (c3 == 0x43)                // Korean (single- and multi-byte)
+                            key = "ISO 2022 IR 149";
+                        else if (c3 == 0x41)           // Simplified Chinese (multi-byte)
+                            key = "ISO 2022 IR 58";
+                    }
+                }
+                // check whether a valid escape sequence has been found
+                if (key.empty())
+                {
+                    OFOStringStream stream;
+                    stream << "Cannot convert character set: Illegal escape sequence 'ESC "
+                        << STD_NAMESPACE dec << STD_NAMESPACE setfill('0')
+                        << STD_NAMESPACE setw(2) << OFstatic_cast(int, c1 >> 4) << "/"
+                        << STD_NAMESPACE setw(2) << OFstatic_cast(int, c1 & 0x0f) << " "
+                        << STD_NAMESPACE setw(2) << OFstatic_cast(int, c2 >> 4) << "/"
+                        << STD_NAMESPACE setw(2) << OFstatic_cast(int, c2 & 0x0f);
+                    if (escLength == 3)
+                    {
+                        stream << " " << STD_NAMESPACE setw(2) << OFstatic_cast(int, c3 >> 4) << "/"
+                            << STD_NAMESPACE setw(2) << OFstatic_cast(int, c3 & 0x0f);
+                    }
+                    stream  << "' found" << OFStringStream_ends;
+                    OFSTRINGSTREAM_GETOFSTRING(stream, message)
+                    status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
+                }
+                if (status.good())
+                {
+                    DCMDATA_TRACE("  Switching to character set '" << key << "'");
+                    T_EncodingConvertersMap::const_iterator it = EncodingConverters.find(key);
+                    // check whether the descriptor was found in the map, i.e. properly declared in (0008,0005)
+                    if (it != EncodingConverters.end())
+                    {
+                        converter = it->second;
+                        // special case: these Japanese character sets replace the ASCII part (G0 code area),
+                        // so according to DICOM PS 3.5 Section 6.2.1.2 an explicit switch to the default is required
+                        checkDelimiters = (key != "ISO 2022 IR 87") && (key != "ISO 2022 IR 159");
+                        // determine number of bytes per character (used by the selected character set)
+                        if ((key == "ISO 2022 IR 87") || (key == "ISO 2022 IR 159") || (key == "ISO 2022 IR 58"))
+                        {
+                            DCMDATA_TRACE("    Now using 2 bytes per character");
+                            bytesPerChar = 2;
+                        }
+                        else if (key == "ISO 2022 IR 149")
+                        {
+                            DCMDATA_TRACE("    Now using 1 or 2 bytes per character");
+                            bytesPerChar = 0;      // special handling for single- and multi-byte
+                        } else {
+                            DCMDATA_TRACE("    Now using 1 byte per character");
+                            bytesPerChar = 1;
+                        }
+                    } else {
+                        OFOStringStream stream;
+                        stream << "Cannot convert character set: Escape sequence refers to character set '" << key << "' that "
+                            "was not declared in SpecificCharacterSet (0008,0005)" << OFStringStream_ends;
+                        OFSTRINGSTREAM_GETOFSTRING(stream, message)
+                        status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
+                    }
+                }
+                pos += escLength;
+            }
+            // check whether the escape sequence was complete
+            if (status.good() && (pos >= fromLength))
+            {
+                OFOStringStream stream;
+                stream << "Cannot convert character set: Incomplete escape sequence (" << (escLength + 1)
+                    << " bytes expected) at the end of the string to be converted" << OFStringStream_ends;
+                OFSTRINGSTREAM_GETOFSTRING(stream, message)
+                status = makeOFCondition(OFM_dcmdata, EC_CODE_CannotConvertCharacterSet, OF_error, message.c_str());
+            }
+            // do not copy the escape sequence to the output
+            firstChar = currentChar;
+        }
+        // the HT, LF, FF, CR character or other delimiters (depending on the VR) also cause a switch
+        else if (isDelimiter)
+        {
+            // output some debug information
+            DCMDATA_TRACE("    Appending delimiter '"
+                << convertToLengthLimitedOctalString(currentChar - 1 /* identical to c0 */, 1)
+                << "' to the output");
+            // don't forget to append the delimiter
+            toString += c0;
+            // use the default descriptor again (see DICOM PS 3.5)
+            if (converter != DefaultEncodingConverter)
+            {
+                DCMDATA_TRACE("  Switching back to the default character set (because a delimiter was found)");
+                converter = DefaultEncodingConverter;
+                checkDelimiters = OFTrue;
+            }
+            // start new sub-string after delimiter
+            firstChar = currentChar;
+        }
+        // skip remaining bytes of current character (if any)
+        else if (bytesPerChar != 1)
+        {
+            const size_t skipBytes = (bytesPerChar > 0) ? (bytesPerChar - 1) : ((c0 & 0x80) ? 1 : 0);
+            if (pos + skipBytes < fromLength)
+                currentChar += skipBytes;
+            pos += skipBytes;
+        }
+        ++pos;
     }
     if (status.good())
     {
-        // finally, output some debug information
-        if (DestinationEncoding == "UTF-8")
+        // convert any remaining characters from the input string
+        const size_t convertLength = currentChar - firstChar;
+        if (convertLength > 0)
         {
-            // output code points only in case of UTF-8 output
-            DCMDATA_TRACE("Converted result in " << DestinationEncoding << " is '"
-                << convertToLengthLimitedOctalString(toString.c_str(), toString.length()) << "' ("
-                << countCharactersInUTF8String(toString) << " code points)");
-        } else {
-            DCMDATA_TRACE("Converted result in " << DestinationEncoding << " is '"
-                << convertToLengthLimitedOctalString(toString.c_str(), toString.length()) << "'");
+            // output some debug information
+            DCMDATA_TRACE("    Converting remaining sub-string '"
+                << convertToLengthLimitedOctalString(firstChar, convertLength) << "'");
+            status = converter.convertString(firstChar, convertLength, toString, OFFalse /*clearMode*/);
+            if (status.bad())
+                DCMDATA_TRACE("    -> ERROR: " << status.text());
         }
     }
     return status;
 }
 
 
-OFBool DcmSpecificCharacterSet::isConversionAvailable()
-{
-    // just call the appropriate function from the underlying class
-    return OFCharacterEncoding::isLibraryAvailable();
-}
-
-
-size_t DcmSpecificCharacterSet::countCharactersInUTF8String(const OFString &utf8String)
-{
-    // just call the appropriate function from the underlying class
-    return OFCharacterEncoding::countCharactersInUTF8String(utf8String);
-}
 
 
 OFBool DcmSpecificCharacterSet::checkForEscapeCharacter(const char *strValue,
@@ -905,3 +920,19 @@ OFString DcmSpecificCharacterSet::convertToLengthLimitedOctalString(const char *
     // return string by-value (in order to avoid another parameter)
     return octalString;
 }
+
+
+// static helper functions
+
+OFBool DcmSpecificCharacterSet::isConversionAvailable()
+{
+    // just call the appropriate function from the underlying class
+    return OFCharacterEncoding::isLibraryAvailable();
+}
+
+
+size_t DcmSpecificCharacterSet::countCharactersInUTF8String(const OFString &utf8String)
+{
+    // just call the appropriate function from the underlying class
+    return OFCharacterEncoding::countCharactersInUTF8String(utf8String);
+}
index 93eeeba7a26e4f73c1df8134f5001339e8923185..be463a81484a9adc1d426ea7670f9770dddaf41c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -35,9 +35,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SOCKET_H
 #ifndef DCOMPAT_SYS_SOCKET_H_
 #define DCOMPAT_SYS_SOCKET_H_
@@ -126,6 +124,7 @@ static const UIDNameMap uidNameMap[] = {
     { UID_JPEGLSLossyTransferSyntax,                                             "JPEGLSNearLossless",                                                 "JPEGLSLossy",                                                        { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
     { UID_RLELosslessTransferSyntax,                                             "RLELossless",                                                        "RLELossless",                                                        { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
     { UID_DeflatedExplicitVRLittleEndianTransferSyntax,                          "DeflatedExplicitVRLittleEndian",                                     "DeflatedLittleEndianExplicit",                                       { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
+    { UID_DeflatedImageFrameCompressionTransferSyntax,                           "DeflatedImageFrameCompression",                                      "DeflatedImageFrameCompression",                                      { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
     { UID_JPEG2000LosslessOnlyTransferSyntax,                                    "JPEG2000Lossless",                                                   "JPEG2000LosslessOnly",                                               { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
     { UID_JPEG2000TransferSyntax,                                                "JPEG2000",                                                           "JPEG2000",                                                           { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
     { UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax, "JPEG2000MCLossless",                                                 "JPEG2000MulticomponentLosslessOnly",                                 { EUS_DICOM, EUV_Standard, EUT_TransferSyntax, EUST_other, EUIT_other, UID_PROP_NONE } },
@@ -327,7 +326,9 @@ static const UIDNameMap uidNameMap[] = {
     { UID_VLSlideCoordinatesMicroscopicImageStorage,                             "VLSlideCoordinatesMicroscopicImageStorage",                          "VLSlideCoordinatesMicroscopicImageStorage",                          { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image,             UID_PROP_NONE } },
     { UID_VLWholeSlideMicroscopyImageStorage,                                    "VLWholeSlideMicroscopyImageStorage",                                 "VLWholeSlideMicroscopyImageStorage",                                 { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image,             UID_PROP_ENHANCED_MF } },
     { UID_VolumeRenderingVolumetricPresentationStateStorage,                     "VolumeRenderingVolumetricPresentationStateStorage",                  "VolumeRenderingVolumetricPresentationStateStorage",                  { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_PresentationState, UID_PROP_NONE } },
+    { UID_WaveformAcquisitionPresentationStateStorage,                           "WaveformAcquisitionPresentationStateStorage",                        "WaveformAcquisitionPresentationStateStorage",                        { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_PresentationState, UID_PROP_NONE } },
     { UID_WaveformAnnotationSRStorage,                                           "WaveformAnnotationSRStorage",                                        "WaveformAnnotationSRStorage",                                        { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_StructuredReport,  UID_PROP_NONE } },
+    { UID_WaveformPresentationStateStorage,                                      "WaveformPresentationStateStorage",                                   "WaveformPresentationStateStorage",                                   { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_PresentationState, UID_PROP_NONE } },
     { UID_WideFieldOphthalmicPhotographyStereographicProjectionImageStorage,     "WideFieldOphthalmicPhotographyStereographicProjectionImageStorage",  "WideFieldOphthalmicPhotographyStereographicProjectionImageStorage",  { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image,             UID_PROP_NONE } },
     { UID_WideFieldOphthalmicPhotography3DCoordinatesImageStorage,               "WideFieldOphthalmicPhotography3DCoordinatesImageStorage",            "WideFieldOphthalmicPhotography3DCoordinatesImageStorage",            { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image,             UID_PROP_NONE } },
     { UID_XADefinedProcedureProtocolStorage,                                     "XADefinedProcedureProtocolStorage",                                  "XADefinedProcedureProtocolStorage",                                  { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_other,             UID_PROP_NON_PATIENT | UID_PROP_NO_DIR_RECORD } },
@@ -366,6 +367,7 @@ static const UIDNameMap uidNameMap[] = {
     { UID_DICONDE_EddyCurrentMultiframeImageStorage,                             "EddyCurrentMultiFrameImageStorage",                                  "DICONDE_EddyCurrentMultiframeImageStorage",                          { EUS_DICONDE, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image, UID_PROP_NONE } },
     { UID_DICONDE_ThermographyImageStorage,                                      "ThermographyImageStorage",                                           "DICONDE_ThermographyImageStorage",                                   { EUS_DICONDE, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image, UID_PROP_NONE } },
     { UID_DICONDE_ThermographyMultiFrameImageStorage,                            "ThermographyMultiFrameImageStorage",                                 "DICONDE_ThermographyMultiFrameImageStorage",                         { EUS_DICONDE, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Image, UID_PROP_NONE } },
+    { UID_DICONDE_UltrasoundWaveformStorage,                                     "UltrasoundWaveformStorage",                                          "DICONDE_UltrasoundWaveformStorage",                                  { EUS_DICONDE, EUV_Standard, EUT_SOPClass, EUST_Storage, EUIT_Waveform, UID_PROP_NONE } },
 
     // Query/Retrieve
     { UID_FINDPatientRootQueryRetrieveInformationModel,                          "PatientRootQueryRetrieveInformationModelFind",                       "FINDPatientRootQueryRetrieveInformationModel",                       { EUS_DICOM, EUV_Standard, EUT_SOPClass, EUST_QueryRetrieve, EUIT_other, UID_PROP_NONE } },
@@ -642,10 +644,7 @@ static const UIDNameMap uidNameMap[] = {
     { UID_DRAFT_UnifiedProcedureStepPushSOPClass,                                "UnifiedProcedureStepPushTrial",                                      "DRAFT_UnifiedProcedureStepPushSOPClass",                             { EUS_DICOM, EUV_Draft, EUT_SOPClass,     EUST_other,   EUIT_other,            UID_PROP_NONE } },
     { UID_DRAFT_UnifiedProcedureStepWatchSOPClass,                               "UnifiedProcedureStepWatchTrial",                                     "DRAFT_UnifiedProcedureStepWatchSOPClass",                            { EUS_DICOM, EUV_Draft, EUT_SOPClass,     EUST_other,   EUIT_other,            UID_PROP_NONE } },
     { UID_DRAFT_UnifiedProcedureStepPullSOPClass,                                "UnifiedProcedureStepPullTrial",                                      "DRAFT_UnifiedProcedureStepPullSOPClass",                             { EUS_DICOM, EUV_Draft, EUT_SOPClass,     EUST_other,   EUIT_other,            UID_PROP_NONE } },
-    { UID_DRAFT_UnifiedProcedureStepEventSOPClass,                               "UnifiedProcedureStepEventTrial",                                     "DRAFT_UnifiedProcedureStepEventSOPClass",                            { EUS_DICOM, EUV_Draft, EUT_SOPClass,     EUST_other,   EUIT_other,            UID_PROP_NONE } },
-
-    // end of the list
-    { NULL, NULL, NULL, { EUS_other, EUV_other, EUT_other, EUST_other, EUIT_other, UID_PROP_NONE } }
+    { UID_DRAFT_UnifiedProcedureStepEventSOPClass,                               "UnifiedProcedureStepEventTrial",                                     "DRAFT_UnifiedProcedureStepEventSOPClass",                            { EUS_DICOM, EUV_Draft, EUT_SOPClass,     EUST_other,   EUIT_other,            UID_PROP_NONE } }
 };
 
 static const int uidNameMap_size = OFstatic_cast(int, sizeof(uidNameMap) / sizeof(UIDNameMap));
@@ -820,7 +819,9 @@ const char* dcmAllStorageSOPClassUIDs[] = {
     UID_VLSlideCoordinatesMicroscopicImageStorage,
     UID_VLWholeSlideMicroscopyImageStorage,
     UID_VolumeRenderingVolumetricPresentationStateStorage,
+    UID_WaveformAcquisitionPresentationStateStorage,
     UID_WaveformAnnotationSRStorage,
+    UID_WaveformPresentationStateStorage,
     UID_WideFieldOphthalmicPhotographyStereographicProjectionImageStorage,
     UID_WideFieldOphthalmicPhotography3DCoordinatesImageStorage,
     UID_XAPerformedProcedureProtocolStorage,
@@ -867,6 +868,7 @@ const char* dcmAllStorageSOPClassUIDs[] = {
     UID_DICONDE_EddyCurrentMultiframeImageStorage,
     UID_DICONDE_ThermographyImageStorage,
     UID_DICONDE_ThermographyMultiFrameImageStorage,
+    UID_DICONDE_UltrasoundWaveformStorage,
     NULL
 };
 
@@ -1066,7 +1068,9 @@ const char* dcmLongSCUStorageSOPClassUIDs[] = {
 //  UID_TractographyResultsStorage,
 //  UID_VariableModalityLUTSoftcopyPresentationStateStorage,
 //  UID_VolumeRenderingVolumetricPresentationStateStorage,
+//  UID_WaveformAcquisitionPresentationStateStorage,
 //  UID_WaveformAnnotationSRStorage,
+//  UID_WaveformPresentationStateStorage,
 //  UID_WideFieldOphthalmicPhotographyStereographicProjectionImageStorage,
 //  UID_WideFieldOphthalmicPhotography3DCoordinatesImageStorage,
 //  UID_XAPerformedProcedureProtocolStorage,
@@ -1115,6 +1119,7 @@ const char* dcmLongSCUStorageSOPClassUIDs[] = {
 //  UID_DICONDE_EddyCurrentMultiframeImageStorage,
 //  UID_DICONDE_ThermographyImageStorage,
 //  UID_DICONDE_ThermographyMultiFrameImageStorage,
+//  UID_DICONDE_UltrasoundWaveformStorage,
     NULL
 };
 
@@ -1491,7 +1496,9 @@ static const DcmModalityTable modalities[] = {
     { UID_VLSlideCoordinatesMicroscopicImageStorage,               "VLs",  768 * 576 * 3 },
     { UID_VLWholeSlideMicroscopyImageStorage,                      "VLw",  10000 * 10000 * 3 },
     { UID_VolumeRenderingVolumetricPresentationStateStorage,       "VPv",  4096 },
+    { UID_WaveformAcquisitionPresentationStateStorage,             "PSq",  4096 },
     { UID_WaveformAnnotationSRStorage,                             "SRw",  4096 },
+    { UID_WaveformPresentationStateStorage,                        "PSw",  4096 },
     { UID_WideFieldOphthalmicPhotographyStereographicProjectionImageStorage, "OWs", 768 * 576 * 3 },
     { UID_WideFieldOphthalmicPhotography3DCoordinatesImageStorage, "OW3",  768 * 576 * 3 },
     { UID_XADefinedProcedureProtocolStorage,                       "PPxd", 4096 },
@@ -1536,7 +1543,8 @@ static const DcmModalityTable modalities[] = {
     { UID_DICONDE_EddyCurrentImageStorage,                         "EC",   512 * 512 },
     { UID_DICONDE_EddyCurrentMultiframeImageStorage,               "ECm",  512 * 512 },
     { UID_DICONDE_ThermographyImageStorage,                        "TG",   512 * 512 },
-    { UID_DICONDE_ThermographyMultiFrameImageStorage,              "TGm",  512 * 512 }
+    { UID_DICONDE_ThermographyMultiFrameImageStorage,              "TGm",  512 * 512 },
+    { UID_DICONDE_UltrasoundWaveformStorage,                       "UW",   4096 }
 };
 
 static const int numberOfDcmModalityTableEntries = OFstatic_cast(int, sizeof(modalities) / sizeof(DcmModalityTable));
@@ -1546,7 +1554,6 @@ static const int numberOfDcmModalityTableEntries = OFstatic_cast(int, sizeof(mod
  * Public Function Prototypes
  */
 
-
 const char *dcmSOPClassUIDToModality(const char *sopClassUID,
                                      const char *defaultValue)
 {
@@ -1595,6 +1602,7 @@ dcmFindNameOfUID(const char* uid, const char* defaultValue)
     return defaultValue;
 }
 
+
 /*
 ** dcmFindUIDFromName(const char* name)
 ** Return the UID of a name.
@@ -1632,6 +1640,7 @@ dcmFindKeywordOfUID(const char* uid, const char* defaultValue)
     return defaultValue;
 }
 
+
 /*
 ** dcmFindUIDFromKeyword(const char* keyword)
 ** Return the UID of a keyword.
index 29a7ae598ed47f72c7772c7dd23e394cf176e949..2fa82d93601735d3bbf5dd362fb6f5921352f2d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2022, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -280,6 +280,8 @@ OFCondition DcmDecimalString::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
                                         DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
     OFBool isValid;
@@ -287,11 +289,11 @@ OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
     if (!isEmpty())
     {
         /* write element value */
-        OFString bulkDataValue;
-        if (format.asBulkDataURI(getTag(), bulkDataValue))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, bulkDataValue);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
@@ -300,7 +302,7 @@ OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
             {
                 OFString value;
                 OFString vmstring = "1";
-                OFCondition status = getOFString(value, 0L);
+                status = getOFString(value, 0L);
                 if (status.bad())
                     return status;
                 format.printValuePrefix(out);
@@ -309,14 +311,28 @@ OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
                 switch (format.getJsonNumStringPolicy())
                 {
                   case DcmJsonFormat::NSP_auto:
-                    if (isValid) DcmJsonFormat::printNumberDecimal(out, value);
-                    else DcmJsonFormat::printValueString(out, value);
+                    if (isValid)
+                        DcmJsonFormat::printNumberDecimal(out, value);
+                    else
+                    {
+                        DCMDATA_WARN("encountered illegal DS value '" << value << "', converting to JSON string");
+                        DcmJsonFormat::printValueString(out, value);
+                    }
                     break;
                   case DcmJsonFormat::NSP_always_number:
-                    if (isValid) DcmJsonFormat::printNumberDecimal(out, value);
-                    else return EC_CannotWriteStringAsJsonNumber;
+                    if (isValid)
+                        DcmJsonFormat::printNumberDecimal(out, value);
+                    else
+                    {
+                        DCMDATA_WARN("encountered illegal DS value '" << value << "', aborting conversion to JSON");
+                        return EC_CannotWriteStringAsJSONNumber;
+                    }
                     break;
                   case DcmJsonFormat::NSP_always_string:
+                    if (!isValid)
+                    {
+                        DCMDATA_WARN("encountered illegal DS value '" << value << "', converting to JSON string");
+                    }
                     DcmJsonFormat::printValueString(out, value);
                     break;
                 }
@@ -332,14 +348,28 @@ OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
                     switch (format.getJsonNumStringPolicy())
                     {
                       case DcmJsonFormat::NSP_auto:
-                        if (isValid) DcmJsonFormat::printNumberDecimal(out, value);
-                        else DcmJsonFormat::printValueString(out, value);
+                        if (isValid)
+                            DcmJsonFormat::printNumberDecimal(out, value);
+                        else
+                        {
+                            DCMDATA_WARN("encountered illegal DS value '" << value << "', converting to JSON string");
+                            DcmJsonFormat::printValueString(out, value);
+                        }
                         break;
                       case DcmJsonFormat::NSP_always_number:
-                        if (isValid) DcmJsonFormat::printNumberDecimal(out, value);
-                        else return EC_CannotWriteStringAsJsonNumber;
+                        if (isValid)
+                            DcmJsonFormat::printNumberDecimal(out, value);
+                        else
+                        {
+                            DCMDATA_WARN("encountered illegal DS value '" << value << "', aborting conversion to JSON");
+                            return EC_CannotWriteStringAsJSONNumber;
+                        }
                         break;
                       case DcmJsonFormat::NSP_always_string:
+                        if (!isValid)
+                        {
+                            DCMDATA_WARN("encountered illegal DS value '" << value << "', converting to JSON string");
+                        }
                         DcmJsonFormat::printValueString(out, value);
                         break;
                     }
@@ -351,8 +381,7 @@ OFCondition DcmDecimalString::writeJson(STD_NAMESPACE ostream &out,
 
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return status;
 }
 
 
index 182d399428c86af6c5fde5b439a3116bb549fde9..ce085516638aa17122a83b8b5048b26a38a53462 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -398,12 +398,14 @@ OFBool DcmFloatingPointDouble::matches(const DcmElement& candidate,
 OFCondition DcmFloatingPointDouble::writeJson(STD_NAMESPACE ostream &out,
                                               DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
+
     /* write element value (if non-empty) */
     if (!isEmpty())
     {
-        OFCondition status;
         const unsigned long vm = getVM();
 
         if (! format.getJsonExtensionEnabled())
@@ -419,14 +421,15 @@ OFCondition DcmFloatingPointDouble::writeJson(STD_NAMESPACE ostream &out,
           }
         }
 
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
+            OFString value;
             status = getOFString(value, 0L);
             if (status.bad()) return status;
             format.printValuePrefix(out);
@@ -443,6 +446,5 @@ OFCondition DcmFloatingPointDouble::writeJson(STD_NAMESPACE ostream &out,
     }
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return status;
 }
index 78b78894390a7c75e140505e8d3a2de7ffb81697..1b2e591515342a2e9ddb7e64a551d45cc054ecc1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2021, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -400,12 +400,14 @@ OFBool DcmFloatingPointSingle::matches(const DcmElement& candidate,
 OFCondition DcmFloatingPointSingle::writeJson(STD_NAMESPACE ostream &out,
                                               DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
+
     /* write element value (if non-empty) */
     if (!isEmpty())
     {
-        OFCondition status;
         const unsigned long vm = getVM();
 
         if (! format.getJsonExtensionEnabled())
@@ -421,14 +423,15 @@ OFCondition DcmFloatingPointSingle::writeJson(STD_NAMESPACE ostream &out,
           }
         }
 
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
+            OFString value;
             status = getOFString(value, 0L);
             if (status.bad()) return status;
             format.printValuePrefix(out);
@@ -443,8 +446,8 @@ OFCondition DcmFloatingPointSingle::writeJson(STD_NAMESPACE ostream &out,
             format.printValueSuffix(out);
         }
     }
+
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return status;
 }
index 330880dbd74ca3dc5d83fba978ff4b8f3ea347d5..d94b2373374fb6161489d91c2af2f407e876a0f7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2022, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -147,6 +147,8 @@ OFCondition DcmIntegerString::checkStringValue(const OFString &value,
 OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
                                         DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
     OFBool isValid;
@@ -154,11 +156,11 @@ OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
     if (!isEmpty())
     {
         /* write element value */
-        OFString bulkDataValue;
-        if (format.asBulkDataURI(getTag(), bulkDataValue))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, bulkDataValue);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
@@ -167,7 +169,7 @@ OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
             {
                 OFString value;
                 OFString vmstring = "1";
-                OFCondition status = getOFString(value, 0L);
+                status = getOFString(value, 0L);
                 if (status.bad())
                     return status;
                 format.printValuePrefix(out);
@@ -176,14 +178,27 @@ OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
                 switch (format.getJsonNumStringPolicy())
                 {
                   case DcmJsonFormat::NSP_auto:
-                    if (isValid) DcmJsonFormat::printNumberInteger(out, value);
-                    else DcmJsonFormat::printValueString(out, value);
+                    if (isValid)
+                        DcmJsonFormat::printNumberInteger(out, value);
+                    else
+                    {
+                        DCMDATA_WARN("encountered illegal IS value '" << value << "', converting to JSON string");
+                        DcmJsonFormat::printValueString(out, value);
+                    }
                     break;
                   case DcmJsonFormat::NSP_always_number:
                     if (isValid) DcmJsonFormat::printNumberInteger(out, value);
-                    else return EC_CannotWriteStringAsJsonNumber;
+                    else
+                    {
+                        DCMDATA_WARN("encountered illegal IS value '" << value << "', aborting conversion to JSON");
+                        return EC_CannotWriteStringAsJSONNumber;
+                    }
                     break;
                   case DcmJsonFormat::NSP_always_string:
+                    if (!isValid)
+                    {
+                        DCMDATA_WARN("encountered illegal IS value '" << value << "', converting to JSON string");
+                    }
                     DcmJsonFormat::printValueString(out, value);
                     break;
                 }
@@ -199,14 +214,28 @@ OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
                     switch (format.getJsonNumStringPolicy())
                     {
                       case DcmJsonFormat::NSP_auto:
-                        if (isValid) DcmJsonFormat::printNumberInteger(out, value);
-                        else DcmJsonFormat::printValueString(out, value);
+                        if (isValid)
+                            DcmJsonFormat::printNumberInteger(out, value);
+                        else
+                        {
+                            DCMDATA_WARN("encountered illegal IS value '" << value << "', converting to JSON string");
+                            DcmJsonFormat::printValueString(out, value);
+                        }
                         break;
                       case DcmJsonFormat::NSP_always_number:
-                        if (isValid) DcmJsonFormat::printNumberInteger(out, value);
-                        else return EC_CannotWriteStringAsJsonNumber;
+                        if (isValid)
+                            DcmJsonFormat::printNumberInteger(out, value);
+                        else
+                        {
+                            DCMDATA_WARN("encountered illegal IS value '" << value << "', aborting conversion to JSON");
+                            return EC_CannotWriteStringAsJSONNumber;
+                        }
                         break;
                       case DcmJsonFormat::NSP_always_string:
+                        if (!isValid)
+                        {
+                            DCMDATA_WARN("encountered illegal IS value '" << value << "', converting to JSON string");
+                        }
                         DcmJsonFormat::printValueString(out, value);
                         break;
                     }
@@ -219,5 +248,5 @@ OFCondition DcmIntegerString::writeJson(STD_NAMESPACE ostream &out,
     /* write JSON Closer  */
     writeJsonCloser(out, format);
     /* always report success */
-    return EC_Normal;
+    return status;
 }
index e46618e19de9fe622a5ebcd70e3f2661fe09419b..d58ddc01184f1b63c9168140e45c6d8550f14dad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -98,7 +98,7 @@ int DcmOtherByteOtherWord::compare(const DcmElement& rhs) const
      * swapping is applied as necessary. */
     void* thisData = myThis->getValue();
     void* rhsData = myRhs->getValue();
-    return memcmp(thisData, rhsData, thisLength);
+    return compareValues(thisData, rhsData, thisLength);
 }
 
 
@@ -848,31 +848,44 @@ OFCondition DcmOtherByteOtherWord::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmOtherByteOtherWord::writeJson(STD_NAMESPACE ostream &out,
                                              DcmJsonFormat &format)
 {
+    OFCondition result = EC_Normal;
+
     /* write JSON Opener */
     writeJsonOpener(out, format);
+
     /* for an empty value field, we do not need to do anything */
     if (getLengthField() > 0)
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
-        {
-            /* return defined BulkDataURI */
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
-        }
-        else
-        {
-            /* encode binary data as Base64 */
-            format.printInlineBinaryPrefix(out);
-            out << "\"";
-            /* adjust byte order to little endian */
-            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
-            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField()));
-            out << "\"";
-        }
+        /* adjust byte order to little endian */
+        Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+        result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues);
     }
+
     /* write JSON Closer */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
+}
+
+
+// ********************************
+
+int DcmOtherByteOtherWord::compareValues(const void* myValue,
+                                         const void* rhsValue,
+                                         const unsigned long valLength) const
+{
+    /* check for null pointers before comparing */
+    if (myValue == OFnullptr || rhsValue == OFnullptr)
+    {
+        /* handle null pointers appropriately, e.g., treat null as less than non-null */
+        if (myValue == OFnullptr && rhsValue == OFnullptr)
+            return 0; // both are null, considered equal
+        else if (myValue == OFnullptr)
+            return -1; // null is less than non-null
+        else
+            return 1; // non-null is greater than null
+    }
+    else {
+        /* Proceed with the comparison */
+        return memcmp(myValue, rhsValue, valLength);
+    }
 }
index b657ffdb053a200c3a42f4bfd81cedef23774b1c..76970f96ecd927bcebc096d02b1091fffa3d5aa8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2013-2020, OFFIS e.V.
+ *  Copyright (C) 2013-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/ofstd/ofuuid.h"
 #include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/ofstd/ofmath.h"
 
 #include "dcmtk/dcmdata/dcvrod.h"
 #include "dcmtk/dcmdata/dcswap.h"
 #include "dcmtk/dcmdata/dcjson.h"
 
+#include <cmath>
 
 // ********************************
 
@@ -95,6 +97,15 @@ unsigned long DcmOtherDouble::getVM()
 
 // ********************************
 
+/* need to check for "Not a Number" in order to avoid possible output of "-nan" */
+static inline void checkAndOutputFloatValue(STD_NAMESPACE ostream &out,
+                                            const Float64 value)
+{
+    if (OFMath::isnan(value))
+        out << "nan";
+    else
+        out << value;
+}
 
 OFCondition DcmOtherDouble::writeXML(STD_NAMESPACE ostream &out,
                                     const size_t flags)
@@ -140,12 +151,18 @@ OFCondition DcmOtherDouble::writeXML(STD_NAMESPACE ostream &out,
                 {
                     /* increase default precision - see DcmFloatingPointDouble::print() */
                     const STD_NAMESPACE streamsize oldPrecision = out.precision(17);
+                    /* use the standard "C" locale for proper decimal point */
+                    const STD_NAMESPACE locale oldLocale = out.imbue(STD_NAMESPACE locale("C"));
                     /* print float values with separators */
-                    out << (*(floatValues++));
+                    checkAndOutputFloatValue(out, *(floatValues++));
                     for (unsigned long i = 1; i < count; i++)
-                        out << "\\" << (*(floatValues++));
-                    /* reset i/o manipulators */
+                    {
+                        out << "\\";
+                        checkAndOutputFloatValue(out, *(floatValues++));
+                    }
+                    /* reset i/o manipulators and locale */
                     out.precision(oldPrecision);
+                    out.imbue(oldLocale);
                 }
             }
         }
@@ -163,33 +180,22 @@ OFCondition DcmOtherDouble::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmOtherDouble::writeJson(STD_NAMESPACE ostream &out,
                                       DcmJsonFormat &format)
 {
-    /* always write JSON Opener */
+    OFCondition result = EC_Normal;
+
+    /* write JSON Opener */
     writeJsonOpener(out, format);
+
     /* for an empty value field, we do not need to do anything */
     if (getLengthField() > 0)
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
-        {
-            /* return defined BulkDataURI */
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
-        }
-        else
-        {
-            /* encode binary data as Base64 */
-            format.printInlineBinaryPrefix(out);
-            out << "\"";
-            /* adjust byte order to little endian */
-            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
-            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField()));
-            out << "\"";
-        }
+        /* adjust byte order to little endian */
+        Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+        result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues);
     }
-    /* write JSON Closer  */
+
+    /* write JSON Closer */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
index 2661b0bc8de329051415a856e96c05614f683f49..5e1bdeb6263397eae0c8b1b404edcd8fade86135 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2020, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/ofstd/ofuuid.h"
 #include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/ofstd/ofmath.h"
 
 #include "dcmtk/dcmdata/dcjson.h"
 #include "dcmtk/dcmdata/dcvrof.h"
 #include "dcmtk/dcmdata/dcswap.h"
 
+#include <cmath>
 
 // ********************************
 
@@ -95,6 +97,15 @@ unsigned long DcmOtherFloat::getVM()
 
 // ********************************
 
+/* need to check for "Not a Number" in order to avoid possible output of "-nan" */
+static inline void checkAndOutputFloatValue(STD_NAMESPACE ostream &out,
+                                            const Float32 value)
+{
+    if (OFMath::isnan(value))
+        out << "nan";
+    else
+        out << value;
+}
 
 OFCondition DcmOtherFloat::writeXML(STD_NAMESPACE ostream &out,
                                     const size_t flags)
@@ -139,13 +150,19 @@ OFCondition DcmOtherFloat::writeXML(STD_NAMESPACE ostream &out,
                 if (count > 0)
                 {
                     /* increase default precision - see DcmFloatingPointSingle::print() */
-                    const STD_NAMESPACE streamsize oldPrecision = out.precision(8);
+                    const STD_NAMESPACE streamsize oldPrecision = out.precision(9);
+                    /* use the standard "C" locale for proper decimal point */
+                    const STD_NAMESPACE locale oldLocale = out.imbue(STD_NAMESPACE locale("C"));
                     /* print float values with separators */
-                    out << (*(floatValues++));
+                    checkAndOutputFloatValue(out, *(floatValues++));
                     for (unsigned long i = 1; i < count; i++)
-                        out << "\\" << (*(floatValues++));
-                    /* reset i/o manipulators */
+                    {
+                        out << "\\";
+                        checkAndOutputFloatValue(out, *(floatValues++));
+                    }
+                    /* reset i/o manipulators and locale */
                     out.precision(oldPrecision);
+                    out.imbue(oldLocale);
                 }
             }
         }
@@ -163,33 +180,22 @@ OFCondition DcmOtherFloat::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmOtherFloat::writeJson(STD_NAMESPACE ostream &out,
                                      DcmJsonFormat &format)
 {
-    /* always write JSON Opener */
+    OFCondition result = EC_Normal;
+
+    /* write JSON Opener */
     writeJsonOpener(out, format);
+
     /* for an empty value field, we do not need to do anything */
     if (getLengthField() > 0)
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
-        {
-            /* return defined BulkDataURI */
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
-        }
-        else
-        {
-            /* encode binary data as Base64 */
-            format.printInlineBinaryPrefix(out);
-            out << "\"";
-            /* adjust byte order to little endian */
-            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
-            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField()));
-            out << "\"";
-        }
+        /* adjust byte order to little endian */
+        Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+        result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues);
     }
-    /* always write JSON Closer */
+
+    /* write JSON Closer */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
index 5a0a37985e1f5ab9c5c66b4286a45d2791aeabfc..d9e137c56323587290a9f5d604f5825824c201c5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2019, OFFIS e.V.
+ *  Copyright (C) 2016-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -165,33 +165,22 @@ OFCondition DcmOtherLong::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmOtherLong::writeJson(STD_NAMESPACE ostream &out,
                                     DcmJsonFormat &format)
 {
+    OFCondition result = EC_Normal;
+
     /* write JSON Opener */
     writeJsonOpener(out, format);
+
     /* for an empty value field, we do not need to do anything */
     if (getLengthField() > 0)
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
-        {
-            /* return defined BulkDataURI */
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
-        }
-        else
-        {
-            /* encode binary data as Base64 */
-            format.printInlineBinaryPrefix(out);
-            out << "\"";
-            /* adjust byte order to little endian */
-            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
-            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField()));
-            out << "\"";
-        }
+        /* adjust byte order to little endian */
+        Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+        result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues);
     }
+
     /* write JSON Closer */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
index 59d14566c223941357e8c67e10bf9c661db9d041..9ade570460fa87a3eacfe290fa26b954dcde4dee 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -165,33 +165,22 @@ OFCondition DcmOther64bitVeryLong::writeXML(STD_NAMESPACE ostream &out,
 OFCondition DcmOther64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
                                              DcmJsonFormat &format)
 {
+    OFCondition result = EC_Normal;
+
     /* write JSON Opener */
     writeJsonOpener(out, format);
+
     /* for an empty value field, we do not need to do anything */
     if (getLengthField() > 0)
     {
-        OFString value;
-        if (format.asBulkDataURI(getTag(), value))
-        {
-            /* return defined BulkDataURI */
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, value);
-        }
-        else
-        {
-            /* encode binary data as Base64 */
-            format.printInlineBinaryPrefix(out);
-            out << "\"";
-            /* adjust byte order to little endian */
-            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
-            OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField()));
-            out << "\"";
-        }
+        /* adjust byte order to little endian */
+        Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+        result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues);
     }
+
     /* write JSON Closer */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return result;
 }
 
 
index fac454898efbc4c486c20f24a931e339450e96bb..bcb8e06a0ccefb6580a73eea6b8a3889581d0567 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2020, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -86,7 +86,7 @@ int DcmPolymorphOBOW::compare(const DcmElement& rhs) const
         // Get values, always compare in Little Endian byte order (only relevant for OW)
         void* myValue = myThis->getValue(EBO_LittleEndian);
         void* rhsValue = myRhs->getValue(EBO_LittleEndian);
-        result = memcmp(myValue, rhsValue, myLength);
+        result = compareValues(myValue, rhsValue, myLength);
         if (result < 0)
             return -1;
         else if (result > 0)
index 8ced07cf298e52af2ee2cc9067ba01fed56541ce..673726f4426a3e369844a4d858f3fe2ce30efebe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -399,6 +399,8 @@ OFCondition DcmSigned64bitVeryLong::verify(const OFBool autocorrect)
 OFCondition DcmSigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
                                               DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
 
@@ -406,11 +408,11 @@ OFCondition DcmSigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
     {
 
         /* write element value */
-        OFString bulkDataValue;
-        if (format.asBulkDataURI(getTag(), bulkDataValue))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, bulkDataValue);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
@@ -418,7 +420,7 @@ OFCondition DcmSigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
             OFString value;
             Sint64 v = 0;
 
-            OFCondition status = getOFString(value, 0L);
+            status = getOFString(value, 0L);
             if (status.bad()) return status;
             format.printValuePrefix(out);
 
@@ -448,6 +450,5 @@ OFCondition DcmSigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
 
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return status;
 }
index 364acb4468e40ee63b29fe09a487c1e76d5286ea..1f72a027d5c6bffd7717a2b3e0c6d4d6eee98e2e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -398,6 +398,8 @@ OFCondition DcmUnsigned64bitVeryLong::verify(const OFBool autocorrect)
 OFCondition DcmUnsigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
                                                 DcmJsonFormat &format)
 {
+    OFCondition status = EC_Normal;
+
     /* always write JSON Opener */
     writeJsonOpener(out, format);
 
@@ -405,11 +407,11 @@ OFCondition DcmUnsigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
     {
 
         /* write element value */
-        OFString bulkDataValue;
-        if (format.asBulkDataURI(getTag(), bulkDataValue))
+        if (format.asBulkDataURI(getTag(), getLength()))
         {
-            format.printBulkDataURIPrefix(out);
-            DcmJsonFormat::printString(out, bulkDataValue);
+            /* adjust byte order to little endian */
+            Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian));
+            status = format.writeBulkData(out, getTag(), getLengthField(), byteValues);
         }
         else
         {
@@ -417,7 +419,7 @@ OFCondition DcmUnsigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
             OFString value;
             Uint64 v = 0;
 
-            OFCondition status = getOFString(value, 0L);
+            status = getOFString(value, 0L);
             if (status.bad()) return status;
             format.printValuePrefix(out);
 
@@ -447,6 +449,5 @@ OFCondition DcmUnsigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
 
     /* write JSON Closer  */
     writeJsonCloser(out, format);
-    /* always report success */
-    return EC_Normal;
+    return status;
 }
index 166f3a929453c4e8f02180932282866248d6b243..acb8da0871ce82b33fb13fc29b9666b10958a1d7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -24,6 +24,9 @@
 #include "dcmtk/dcmdata/dcuid.h"
 #include <cstring>
 
+#define DCXFER_DEFAULT_MIME_TYPE "application/dicom"
+#define DCXFER_DEFAULT_EXTENSION ".bin"
+
 typedef struct
 {
     const char            *xferID;
@@ -39,6 +42,8 @@ typedef struct
     Uint32                 JPEGProcess12;
     E_StreamCompression    streamCompression;
     E_XferValidity         xferValidity;
+    const char            *mimeType;
+    const char            *filenameExtension;
 } S_XferNames;
 
 
@@ -59,7 +64,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #1
     { "",  // internal type, no UID defined
@@ -73,7 +80,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Internal
+      EXV_Internal,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #2
     { UID_LittleEndianExplicitTransferSyntax,
@@ -87,7 +96,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #3
     { UID_BigEndianExplicitTransferSyntax,
@@ -101,7 +112,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 98
+      EXV_Retired,  // retired with Supplement 98
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #4
     { UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax,
@@ -115,7 +128,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #5
     { UID_JPEGProcess1TransferSyntax,
@@ -129,7 +144,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       1L, 1L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #6
     { UID_JPEGProcess2_4TransferSyntax,
@@ -143,7 +160,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       2L, 4L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #7
     { UID_JPEGProcess3_5TransferSyntax,
@@ -157,7 +176,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       3L, 5L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #8
     { UID_JPEGProcess6_8TransferSyntax,
@@ -171,7 +192,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       6L, 8L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #9
     { UID_JPEGProcess7_9TransferSyntax,
@@ -185,7 +208,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       7L, 9L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #10
     { UID_JPEGProcess10_12TransferSyntax,
@@ -199,7 +224,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       10L, 12L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #11
     { UID_JPEGProcess11_13TransferSyntax,
@@ -213,7 +240,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       11L, 13L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #12
     { UID_JPEGProcess14TransferSyntax,
@@ -227,7 +256,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       14, 14L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #13
     { UID_JPEGProcess15TransferSyntax,
@@ -241,7 +272,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       15L, 15L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #14
     { UID_JPEGProcess16_18TransferSyntax,
@@ -255,7 +288,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       16L, 18L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #15
     { UID_JPEGProcess17_19TransferSyntax,
@@ -269,7 +304,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       17L, 19L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #16
     { UID_JPEGProcess20_22TransferSyntax,
@@ -283,7 +320,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       20L, 22L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #17
     { UID_JPEGProcess21_23TransferSyntax,
@@ -297,7 +336,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       21L, 23L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #18
     { UID_JPEGProcess24_26TransferSyntax,
@@ -311,7 +352,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       24L, 26L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #19
     { UID_JPEGProcess25_27TransferSyntax,
@@ -325,7 +368,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       25L, 27L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #20
     { UID_JPEGProcess28TransferSyntax,
@@ -339,7 +384,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       28L, 28L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #21
     { UID_JPEGProcess29TransferSyntax,
@@ -353,7 +400,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       29L, 29L,
       ESC_none,
-      EXV_Retired  // retired with Supplement 61
+      EXV_Retired,  // retired with Supplement 61
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #22
     { UID_JPEGProcess14SV1TransferSyntax,
@@ -367,7 +416,9 @@ const S_XferNames XferNames[] =
       OFTrue,
       14L, 14L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpeg",
+      ".jpeg"
     },
     // entry #23
     { UID_RLELosslessTransferSyntax,
@@ -381,7 +432,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/dicom-rle",
+      ".dicom-rle"
     },
     // entry #24
     { UID_DeflatedExplicitVRLittleEndianTransferSyntax,
@@ -399,9 +452,27 @@ const S_XferNames XferNames[] =
 #else
       ESC_unsupported,
 #endif
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
     // entry #25
+    { UID_DeflatedImageFrameCompressionTransferSyntax,
+      "Deflated Image Frame Compression",
+      EXS_DeflatedImageFrameCompression,
+      EBO_LittleEndian,
+      EBO_LittleEndian,
+      EVT_Explicit,
+      EPE_Encapsulated,
+      EPC_LosslessCompressed,
+      OFFalse,
+      0L, 0L,
+      ESC_none,
+      EXV_Standard,
+      "application/x-deflate",
+      ".x-deflate"
+    },
+    // entry #26
     { UID_JPEGLSLosslessTransferSyntax,
       "JPEG-LS Lossless",
       EXS_JPEGLSLossless,
@@ -413,9 +484,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jls",
+      ".jls"
     },
-    // entry #26
+    // entry #27
     { UID_JPEGLSLossyTransferSyntax,
       "JPEG-LS Lossy (Near-lossless)",
       EXS_JPEGLSLossy,
@@ -427,9 +500,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jls",
+      ".jls"
     },
-    // entry #27
+    // entry #28
     { UID_JPEG2000LosslessOnlyTransferSyntax,
       "JPEG 2000 (Lossless only)",
       EXS_JPEG2000LosslessOnly,
@@ -441,9 +516,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jp2",
+      ".jp2"
     },
-    // entry #28
+    // entry #29
     { UID_JPEG2000TransferSyntax,
       "JPEG 2000 (Lossless or Lossy)",
       EXS_JPEG2000,
@@ -455,9 +532,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jp2",
+      ".jp2"
     },
-    // entry #29
+    // entry #30
    { UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax,
       "JPEG 2000 Part 2 Multicomponent Image Compression (Lossless only)",
       EXS_JPEG2000MulticomponentLosslessOnly,
@@ -469,9 +548,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpx",
+      ".jpx"
     },
-    // entry #30
+    // entry #31
    { UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax,
       "JPEG 2000 Part 2 Multicomponent Image Compression (Lossless or Lossy)",
       EXS_JPEG2000Multicomponent,
@@ -483,9 +564,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jpx",
+      ".jpx"
     },
-    // entry #31
+    // entry #32
    { UID_JPIPReferencedTransferSyntax,
       "JPIP Referenced",
       EXS_JPIPReferenced,
@@ -497,9 +580,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
-    // entry #32
+    // entry #33
    { UID_JPIPReferencedDeflateTransferSyntax,
       "JPIP Referenced Deflate",
       EXS_JPIPReferencedDeflate,
@@ -515,9 +600,11 @@ const S_XferNames XferNames[] =
 #else
       ESC_unsupported,
 #endif
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
-    // entry #33
+    // entry #34
     { UID_MPEG2MainProfileAtMainLevelTransferSyntax,
       "MPEG2 Main Profile @ Main Level",  // changed with DICOM 2016e to: MPEG2 Main Profile / Main Level
       EXS_MPEG2MainProfileAtMainLevel,
@@ -529,9 +616,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mpeg",
+      ".mpeg"
     },
-    // entry #34
+    // entry #35
     { UID_FragmentableMPEG2MainProfileMainLevelTransferSyntax,
       "Fragmentable MPEG2 Main Profile / Main Level",
       EXS_FragmentableMPEG2MainProfileMainLevel,
@@ -543,9 +632,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mpeg",
+      ".mpeg"
     },
-    // entry #35
+    // entry #36
     { UID_MPEG2MainProfileAtHighLevelTransferSyntax,
       "MPEG2 Main Profile @ High Level",  // changed with DICOM 2016e to: MPEG2 Main Profile / High Level
       EXS_MPEG2MainProfileAtHighLevel,
@@ -557,9 +648,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mpeg",
+      ".mpeg"
     },
-    // entry #36
+    // entry #37
     { UID_FragmentableMPEG2MainProfileHighLevelTransferSyntax,
       "Fragmentable MPEG2 Main Profile / High Level",
       EXS_FragmentableMPEG2MainProfileHighLevel,
@@ -571,9 +664,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mpeg",
+      ".mpeg"
     },
-    // entry #37
+    // entry #38
     { UID_MPEG4HighProfileLevel4_1TransferSyntax,
       "MPEG-4 AVC/H.264 High Profile / Level 4.1",
       EXS_MPEG4HighProfileLevel4_1,
@@ -585,9 +680,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #38
+    // entry #39
     { UID_FragmentableMPEG4HighProfileLevel4_1TransferSyntax,
       "Fragmentable MPEG-4 AVC/H.264 High Profile / Level 4.1",
       EXS_FragmentableMPEG4HighProfileLevel4_1,
@@ -599,9 +696,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #39
+    // entry #40
     { UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax,
       "MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1",
       EXS_MPEG4BDcompatibleHighProfileLevel4_1,
@@ -613,9 +712,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #40
+    // entry #41
     { UID_FragmentableMPEG4BDcompatibleHighProfileLevel4_1TransferSyntax,
       "Fragmentable MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1",
       EXS_FragmentableMPEG4BDcompatibleHighProfileLevel4_1,
@@ -627,9 +728,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #41
+    // entry #42
     { UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax,
       "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video",
       EXS_MPEG4HighProfileLevel4_2_For2DVideo,
@@ -641,9 +744,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #42
+    // entry #43
     { UID_FragmentableMPEG4HighProfileLevel4_2_For2DVideoTransferSyntax,
       "Fragmentable MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video",
       EXS_FragmentableMPEG4HighProfileLevel4_2_For2DVideo,
@@ -655,9 +760,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #43
+    // entry #44
     { UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax,
       "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video",
       EXS_MPEG4HighProfileLevel4_2_For3DVideo,
@@ -669,9 +776,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #44
+    // entry #45
     { UID_FragmentableMPEG4HighProfileLevel4_2_For3DVideoTransferSyntax,
       "Fragmentable MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video",
       EXS_FragmentableMPEG4HighProfileLevel4_2_For3DVideo,
@@ -683,9 +792,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #45
+    // entry #46
     { UID_MPEG4StereoHighProfileLevel4_2TransferSyntax,
       "MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2",
       EXS_MPEG4StereoHighProfileLevel4_2,
@@ -697,9 +808,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #46
+    // entry #47
     { UID_FragmentableMPEG4StereoHighProfileLevel4_2TransferSyntax,
       "Fragmentable MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2",
       EXS_FragmentableMPEG4StereoHighProfileLevel4_2,
@@ -711,9 +824,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/mp4",
+      ".mp4"
     },
-    // entry #47
+    // entry #48
     { UID_HEVCMainProfileLevel5_1TransferSyntax,
       "HEVC/H.265 Main Profile / Level 5.1",
       EXS_HEVCMainProfileLevel5_1,
@@ -725,9 +840,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/H265",
+      ".H265"
     },
-    // entry #48
+    // entry #49
     { UID_HEVCMain10ProfileLevel5_1TransferSyntax,
       "HEVC/H.265 Main 10 Profile / Level 5.1",
       EXS_HEVCMain10ProfileLevel5_1,
@@ -739,9 +856,11 @@ const S_XferNames XferNames[] =
       OFTrue,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "video/H265",
+      ".H265"
     },
-    // entry #49
+    // entry #50
     { UID_JPEGXLLosslessTransferSyntax,
       "JPEG XL Lossless",
       EXS_JPEGXLLossless,
@@ -753,9 +872,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jxl",
+      ".jxl"
     },
-    // entry #50
+    // entry #51
     { UID_JPEGXLJPEGRecompressionTransferSyntax,
       "JPEG XL JPEG Recompression",
       EXS_JPEGXLJPEGRecompression,
@@ -767,9 +888,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jxl",
+      ".jxl"
     },
-    // entry #51
+    // entry #52
     { UID_JPEGXLTransferSyntax,
       "JPEG XL",
       EXS_JPEGXL,
@@ -781,9 +904,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jxl",
+      ".jxl"
     },
-    // entry #52
+    // entry #53
     { UID_HighThroughputJPEG2000ImageCompressionLosslessOnlyTransferSyntax,
       "High-Throughput JPEG 2000 Image Compression (Lossless Only)",
       EXS_HighThroughputJPEG2000LosslessOnly,
@@ -795,9 +920,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jphc",
+      ".jphc"
     },
-    // entry #53
+    // entry #54
     { UID_HighThroughputJPEG2000RPCLImageCompressionLosslessOnlyTransferSyntax,
       "High-Throughput JPEG 2000 with RPCL Options Image Compression (Lossless Only)",
       EXS_HighThroughputJPEG2000withRPCLOptionsLosslessOnly,
@@ -809,9 +936,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jphc",
+      ".jphc"
     },
-    // entry #54
+    // entry #55
     { UID_HighThroughputJPEG2000ImageCompressionTransferSyntax,
       "High-Throughput JPEG 2000 Image Compression",
       EXS_HighThroughputJPEG2000,
@@ -823,9 +952,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      "image/jphc",
+      ".jphc"
     },
-    // entry #55
+    // entry #56
     { UID_JPIPHTJ2KReferencedTransferSyntax,
       "JPIP HTJ2K Referenced",
       EXS_JPIPHTJ2KReferenced,
@@ -837,9 +968,11 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
-    // entry #56
+    // entry #57
     { UID_JPIPHTJ2KReferencedDeflateTransferSyntax,
       "JPIP HTJ2K Referenced Deflate",
       EXS_JPIPHTJ2KReferencedDeflate,
@@ -855,9 +988,11 @@ const S_XferNames XferNames[] =
 #else
       ESC_unsupported,
 #endif
-      EXV_Standard
+      EXV_Standard,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     },
-    // entry #57
+    // entry #58
     { UID_PrivateGE_LEI_WithBigEndianPixelDataTransferSyntax,
       "Private GE Little Endian Implicit with big endian pixel data",
       EXS_PrivateGE_LEI_WithBigEndianPixelData,
@@ -869,7 +1004,9 @@ const S_XferNames XferNames[] =
       OFFalse,
       0L, 0L,
       ESC_none,
-      EXV_Private
+      EXV_Private,
+      DCXFER_DEFAULT_MIME_TYPE,
+      DCXFER_DEFAULT_EXTENSION
     }
 };
 
@@ -892,7 +1029,9 @@ DcmXfer::DcmXfer(E_TransferSyntax xfer)
     JPEGProcess8(0L),
     JPEGProcess12(0L),
     streamCompression(ESC_none),
-    xferValidity(EXV_unknown)
+    xferValidity(EXV_unknown),
+    mimeType(DCXFER_DEFAULT_MIME_TYPE),
+    filenameExtension(DCXFER_DEFAULT_EXTENSION)
 {
     /* casting the enum to an integer should be safe */
     const int i = OFstatic_cast(int, xfer);
@@ -912,6 +1051,8 @@ DcmXfer::DcmXfer(E_TransferSyntax xfer)
         JPEGProcess12         = XferNames[i].JPEGProcess12;
         streamCompression     = XferNames[i].streamCompression;
         xferValidity          = XferNames[i].xferValidity;
+        mimeType              = XferNames[i].mimeType;
+        filenameExtension     = XferNames[i].filenameExtension;
     }
 }
 
@@ -932,7 +1073,9 @@ DcmXfer::DcmXfer(const char *xferName_xferID)
     JPEGProcess8(0L),
     JPEGProcess12(0L),
     streamCompression(ESC_none),
-    xferValidity(EXV_unknown)
+    xferValidity(EXV_unknown),
+    mimeType(DCXFER_DEFAULT_MIME_TYPE),
+    filenameExtension(DCXFER_DEFAULT_EXTENSION)
 {
     if (xferName_xferID != NULL)
     {
@@ -961,6 +1104,8 @@ DcmXfer::DcmXfer(const char *xferName_xferID)
             JPEGProcess12         = XferNames[i].JPEGProcess12;
             streamCompression     = XferNames[i].streamCompression;
             xferValidity          = XferNames[i].xferValidity;
+            mimeType              = XferNames[i].mimeType;
+            filenameExtension     = XferNames[i].filenameExtension;
         }
     }
 }
@@ -982,7 +1127,9 @@ DcmXfer::DcmXfer(const DcmXfer &newXfer)
     JPEGProcess8(newXfer.JPEGProcess8),
     JPEGProcess12(newXfer.JPEGProcess12),
     streamCompression(newXfer.streamCompression),
-    xferValidity(newXfer.xferValidity)
+    xferValidity(newXfer.xferValidity),
+    mimeType(newXfer.mimeType),
+    filenameExtension(newXfer.filenameExtension)
 {
 }
 
@@ -1018,6 +1165,8 @@ DcmXfer &DcmXfer::operator=(const E_TransferSyntax xfer)
         JPEGProcess12         = XferNames[i].JPEGProcess12;
         streamCompression     = XferNames[i].streamCompression;
         xferValidity          = XferNames[i].xferValidity;
+        mimeType              = XferNames[i].mimeType;
+        filenameExtension     = XferNames[i].filenameExtension;
     } else {
         xferSyn               = EXS_Unknown;
         xferID                = "";
@@ -1032,6 +1181,8 @@ DcmXfer &DcmXfer::operator=(const E_TransferSyntax xfer)
         JPEGProcess12         = 0L;
         streamCompression     = ESC_none;
         xferValidity          = EXV_unknown;
+        mimeType              = DCXFER_DEFAULT_MIME_TYPE;
+        filenameExtension     = DCXFER_DEFAULT_EXTENSION;
     }
     return *this;
 }
@@ -1057,6 +1208,8 @@ DcmXfer &DcmXfer::operator=(const DcmXfer &newXfer)
         JPEGProcess12         = newXfer.JPEGProcess12;
         streamCompression     = newXfer.streamCompression;
         xferValidity          = newXfer.xferValidity;
+        mimeType              = newXfer.mimeType;
+        filenameExtension     = newXfer.filenameExtension;
     }
     return *this;
 }
index c81ce71a3ea9e36ede52317ae3c1873b6621c6a0..36f5e33a2658d6ab2480c6c5ee82a54aa1da6cc4 100644 (file)
@@ -573,7 +573,7 @@ static const YY_CHAR yy_meta[42] =
 
 static const flex_int16_t yy_base[2631] =
     {   0,
-        0,   38, 1130,16740,16740,    0, 1088,    6, 1083,    7,
+        0,   38, 1130,16752,16752,    0, 1088,    6, 1083,    7,
      1053, 1048, 1024,    6,    0, 1019,    1,   36,   46,   38,
        74,   47,    0,  993,   75,   92,    0,   50,    0,   51,
        89,   90,    0,  994,   93,  100,  101,    0,    0,  984,
@@ -750,7 +750,7 @@ static const flex_int16_t yy_base[2631] =
      5407,    0, 5041, 5398, 5412, 5419, 5426, 5431,    4, 5435,
 
      5440, 5445, 5450, 5454, 5459, 5464, 5469, 5473, 5478, 5483,
-     5488, 5492, 5497,16740, 5522, 5537, 5547, 5559, 5567, 5579,
+     5488, 5492, 5497,16752, 5522, 5537, 5547, 5559, 5567, 5579,
      5587, 5600, 5616, 5631, 5646, 5656, 5667, 5681, 5695, 5705,
      5708, 5720, 5728, 5731, 5739, 5746, 5760, 5768, 5771, 5779,
      5786, 5798, 5811, 5826, 5841, 5856, 5866, 5870, 5881, 5893,
@@ -855,13 +855,13 @@ static const flex_int16_t yy_base[2631] =
     16013,16025,16037,16049,16061,16073,16085,16097,16109,16121,
     16133,16145,16157,16169,16181,16193,16205,16217,16229,16241,
     16253,16265,16277,16289,16301,16309,16316,16324,16327,16330,
-    16333, 5307, 5316,16340, 5320, 5381,16352,16360,16363,16370,
-    16378,16385,16393,16396,16399,16402, 5385, 5397,16409, 5420,
-     5497,16421,16429,16436,16444,16447,16450,16453,16456,16459,
+    16333,16336, 5307,16343,16351, 5316,16358,16366,16369,16376,
+    16384,16391,16399,16402,16405,16408,16411, 5320,16418,16426,
+     5381,16433,16441,16448,16456,16459,16462,16465,16468,16471,
 
-    16462,16465,16468,16471,16474,16477,16480,16487,16499,16507,
-    16510,16517,16529,16541,16553,16561,16568,16580,16592,16604,
-    16616,16628,16640,16652,16664,16676,16688,16700,16712,16724
+    16474,16477,16480,16483,16486,16489,16492,16499,16511,16519,
+    16522,16529,16541,16553,16565,16573,16580,16592,16604,16616,
+    16628,16640,16652,16664,16676,16688,16700,16712,16724,16736
     } ;
 
 static const flex_int16_t yy_def[2631] =
@@ -1157,7 +1157,7 @@ static const flex_int16_t yy_def[2631] =
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614
     } ;
 
-static const flex_int16_t yy_nxt[16782] =
+static const flex_int16_t yy_nxt[16794] =
     {   0,
      1614, 1614,    5, 1614,   30,   35, 1614, 1614, 1614, 1614,
       110,  111,  112,  147,  147,  147,  147,   88,   89,  104,
@@ -1743,19 +1743,19 @@ static const flex_int16_t yy_nxt[16782] =
      1547, 1547, 1547, 1547, 1547, 1547, 1547,  486,  242, 1505,
 
      1506, 1556, 1556, 1556, 1556, 1557,  489,  350, 1508, 1509,
-      365, 1614, 1414, 1415, 1566, 1518, 1518,  368,  245,  369,
-     1614, 1417, 1418, 1568, 1520, 1520,   50,  245, 1523, 1523,
+      365, 1614, 1414, 1415, 1566, 1520, 1520,  368,  245,  369,
+     1614, 1417, 1418, 1568, 1525, 1525,   50,  245, 1553, 1553,
       368, 1569, 1569, 1569, 1569, 1569, 1569, 1614,  350,   50,
      1569, 1569, 1569, 1569, 1569, 1569, 1573, 1573, 1573, 1573,
      1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573,  245,  365,
       369,  486, 1585, 1505, 1506, 1582,  489,  486, 1508, 1509,
      1584,  365,  489, 1414, 1415,  369, 1585, 1417, 1418,  368,
-       50,  368, 1586, 1592, 1592, 1593,   50,  368, 1594, 1525,
-     1525,  368,   50, 1551, 1551,   50, 1586,  365, 1586, 1414,
+       50,  368, 1586, 1592, 1592, 1593,   50,  368, 1594, 1558,
+     1558,  368,   50, 1614, 1614,   50, 1586,  365, 1586, 1414,
 
-     1415,  369, 1594, 1417, 1418, 1553, 1553,  486, 1586, 1505,
+     1415,  369, 1594, 1417, 1418, 1614, 1614,  486, 1586, 1505,
      1506,  489, 1614, 1508, 1509, 1614,  365,  368, 1414, 1415,
-     1614,   50, 1586,  369, 1614, 1417, 1418,  368, 1556, 1556,
+     1614,   50, 1586,  369, 1614, 1417, 1418,  368, 1614, 1614,
       486,   50, 1505, 1506, 1614,  489,  368, 1508, 1509,  365,
      1614, 1414, 1415,   50,  369, 1614, 1417, 1418, 1614,  486,
       368, 1505, 1506, 1614,  489,   50, 1508, 1509,  365,  368,
@@ -1764,7 +1764,7 @@ static const flex_int16_t yy_nxt[16782] =
      1415, 1614,  369,   50, 1417, 1418, 1614,  486,  368, 1505,
      1506, 1614,  489,   50, 1508, 1509,  486,  368, 1505, 1506,
 
-     1614,  489,   50, 1508, 1509, 1558, 1558,  368, 1614, 1614,
+     1614,  489,   50, 1508, 1509, 1614, 1614,  368, 1614, 1614,
      1614, 1614,   50, 1614, 1614, 1614,  368, 1614, 1614, 1614,
      1614,   50,    4,    4,    4,    4,    4,    4,    4,    4,
         4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
@@ -2956,58 +2956,60 @@ static const flex_int16_t yy_nxt[16782] =
      1511, 1614, 1614, 1614, 1614, 1511, 1512, 1512, 1512, 1513,
      1614, 1614, 1614, 1513, 1513, 1513, 1614, 1614, 1614, 1614,
      1513, 1514, 1514, 1514, 1515, 1515, 1515, 1516, 1516, 1516,
-     1517, 1517, 1517, 1522, 1614, 1522, 1614, 1522, 1522, 1614,
-     1614, 1614, 1614, 1614, 1522, 1527, 1614, 1527, 1614, 1527,
-     1527, 1614, 1614, 1614, 1614, 1614, 1527, 1532, 1532, 1532,
-     1537, 1537, 1537, 1538, 1614, 1614, 1614, 1538, 1538, 1538,
-     1614, 1614, 1614, 1614, 1538, 1539, 1539, 1539, 1540, 1614,
-     1614, 1614, 1540, 1540, 1540, 1614, 1614, 1614, 1614, 1540,
-
-     1541, 1541, 1541, 1542, 1542, 1542, 1546, 1546, 1546, 1550,
-     1550, 1550, 1555, 1614, 1555, 1614, 1555, 1555, 1614, 1614,
-     1614, 1614, 1614, 1555, 1560, 1614, 1560, 1614, 1560, 1560,
-     1614, 1614, 1614, 1614, 1614, 1560, 1561, 1561, 1561, 1562,
-     1614, 1614, 1614, 1562, 1562, 1562, 1614, 1614, 1614, 1614,
-     1562, 1563, 1563, 1563, 1564, 1564, 1564, 1565, 1565, 1565,
-     1567, 1567, 1567, 1572, 1572, 1572, 1576, 1576, 1576, 1577,
-     1577, 1577, 1578, 1578, 1578, 1579, 1579, 1579, 1580, 1580,
-     1580, 1581, 1581, 1581, 1583, 1583, 1583, 1587, 1587, 1587,
-     1588, 1614, 1588, 1614, 1588, 1588, 1588, 1614, 1614, 1614,
-
-     1614, 1588, 1589, 1614, 1589, 1614, 1589, 1589, 1589, 1614,
-     1614, 1614, 1614, 1589, 1590, 1590, 1590, 1591, 1591, 1591,
-     1595, 1614, 1595, 1614, 1595, 1595, 1595, 1614, 1614, 1614,
-     1614, 1595, 1596, 1614, 1596, 1614, 1596, 1596, 1596, 1614,
-     1614, 1614, 1614, 1596, 1597, 1614, 1597, 1614, 1597, 1597,
-     1597, 1614, 1614, 1614, 1614, 1597, 1598, 1614, 1598, 1614,
-     1598, 1598, 1598, 1614, 1614, 1614, 1614, 1598, 1599, 1599,
-     1599, 1600, 1614, 1600, 1614, 1600, 1600, 1600, 1614, 1614,
-     1614, 1614, 1600, 1601, 1614, 1601, 1614, 1601, 1601, 1601,
-     1614, 1614, 1614, 1614, 1601, 1602, 1614, 1602, 1614, 1602,
-
-     1602, 1602, 1614, 1614, 1614, 1614, 1602, 1603, 1614, 1603,
-     1614, 1603, 1603, 1603, 1614, 1614, 1614, 1614, 1603, 1604,
-     1614, 1604, 1614, 1604, 1604, 1604, 1614, 1614, 1614, 1614,
-     1604, 1605, 1614, 1605, 1614, 1605, 1605, 1605, 1614, 1614,
-     1614, 1614, 1605, 1606, 1614, 1606, 1614, 1606, 1606, 1606,
-     1614, 1614, 1614, 1614, 1606, 1607, 1614, 1607, 1614, 1607,
-     1607, 1607, 1614, 1614, 1614, 1614, 1607, 1608, 1614, 1608,
-     1614, 1608, 1608, 1608, 1614, 1614, 1614, 1614, 1608, 1609,
-     1614, 1609, 1614, 1609, 1609, 1609, 1614, 1614, 1614, 1614,
-     1609, 1610, 1614, 1610, 1614, 1610, 1610, 1610, 1614, 1614,
-
-     1614, 1614, 1610, 1611, 1614, 1611, 1614, 1611, 1611, 1611,
-     1614, 1614, 1614, 1614, 1611, 1612, 1614, 1612, 1614, 1612,
-     1612, 1612, 1614, 1614, 1614, 1614, 1612, 1613, 1614, 1613,
-     1614, 1613, 1613, 1613, 1614, 1614, 1614, 1614, 1613,    3,
+     1517, 1517, 1517, 1518, 1518, 1518, 1522, 1614, 1522, 1614,
+     1522, 1522, 1614, 1614, 1614, 1614, 1614, 1522, 1523, 1523,
+     1523, 1527, 1614, 1527, 1614, 1527, 1527, 1614, 1614, 1614,
+     1614, 1614, 1527, 1532, 1532, 1532, 1537, 1537, 1537, 1538,
+     1614, 1614, 1614, 1538, 1538, 1538, 1614, 1614, 1614, 1614,
+     1538, 1539, 1539, 1539, 1540, 1614, 1614, 1614, 1540, 1540,
+
+     1540, 1614, 1614, 1614, 1614, 1540, 1541, 1541, 1541, 1542,
+     1542, 1542, 1546, 1546, 1546, 1550, 1550, 1550, 1551, 1551,
+     1551, 1555, 1614, 1555, 1614, 1555, 1555, 1614, 1614, 1614,
+     1614, 1614, 1555, 1556, 1556, 1556, 1560, 1614, 1560, 1614,
+     1560, 1560, 1614, 1614, 1614, 1614, 1614, 1560, 1561, 1561,
+     1561, 1562, 1614, 1614, 1614, 1562, 1562, 1562, 1614, 1614,
+     1614, 1614, 1562, 1563, 1563, 1563, 1564, 1564, 1564, 1565,
+     1565, 1565, 1567, 1567, 1567, 1572, 1572, 1572, 1576, 1576,
+     1576, 1577, 1577, 1577, 1578, 1578, 1578, 1579, 1579, 1579,
+     1580, 1580, 1580, 1581, 1581, 1581, 1583, 1583, 1583, 1587,
+
+     1587, 1587, 1588, 1614, 1588, 1614, 1588, 1588, 1588, 1614,
+     1614, 1614, 1614, 1588, 1589, 1614, 1589, 1614, 1589, 1589,
+     1589, 1614, 1614, 1614, 1614, 1589, 1590, 1590, 1590, 1591,
+     1591, 1591, 1595, 1614, 1595, 1614, 1595, 1595, 1595, 1614,
+     1614, 1614, 1614, 1595, 1596, 1614, 1596, 1614, 1596, 1596,
+     1596, 1614, 1614, 1614, 1614, 1596, 1597, 1614, 1597, 1614,
+     1597, 1597, 1597, 1614, 1614, 1614, 1614, 1597, 1598, 1614,
+     1598, 1614, 1598, 1598, 1598, 1614, 1614, 1614, 1614, 1598,
+     1599, 1599, 1599, 1600, 1614, 1600, 1614, 1600, 1600, 1600,
+     1614, 1614, 1614, 1614, 1600, 1601, 1614, 1601, 1614, 1601,
+
+     1601, 1601, 1614, 1614, 1614, 1614, 1601, 1602, 1614, 1602,
+     1614, 1602, 1602, 1602, 1614, 1614, 1614, 1614, 1602, 1603,
+     1614, 1603, 1614, 1603, 1603, 1603, 1614, 1614, 1614, 1614,
+     1603, 1604, 1614, 1604, 1614, 1604, 1604, 1604, 1614, 1614,
+     1614, 1614, 1604, 1605, 1614, 1605, 1614, 1605, 1605, 1605,
+     1614, 1614, 1614, 1614, 1605, 1606, 1614, 1606, 1614, 1606,
+     1606, 1606, 1614, 1614, 1614, 1614, 1606, 1607, 1614, 1607,
+     1614, 1607, 1607, 1607, 1614, 1614, 1614, 1614, 1607, 1608,
+     1614, 1608, 1614, 1608, 1608, 1608, 1614, 1614, 1614, 1614,
+     1608, 1609, 1614, 1609, 1614, 1609, 1609, 1609, 1614, 1614,
+
+     1614, 1614, 1609, 1610, 1614, 1610, 1614, 1610, 1610, 1610,
+     1614, 1614, 1614, 1614, 1610, 1611, 1614, 1611, 1614, 1611,
+     1611, 1611, 1614, 1614, 1614, 1614, 1611, 1612, 1614, 1612,
+     1614, 1612, 1612, 1612, 1614, 1614, 1614, 1614, 1612, 1613,
+     1614, 1613, 1614, 1613, 1613, 1613, 1614, 1614, 1614, 1614,
+     1613,    3, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
-     1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
-     1614
+     1614, 1614, 1614
+
     } ;
 
-static const flex_int16_t yy_chk[16782] =
+static const flex_int16_t yy_chk[16794] =
     {   0,
         0,    0,    1,    0,   15,   17,   43,    0,   43,   43,
        53,   53,   53,   70,   70,   70,   70,   39,   39,   48,
@@ -3593,19 +3595,19 @@ static const flex_int16_t yy_chk[16782] =
      1523, 1525, 1525, 1525, 1525, 1525, 1525, 1532, 1538, 1532,
 
      1532, 1534, 1534, 1534, 1534, 1534, 1537, 1540, 1537, 1537,
-     1546,    0, 1546, 1546, 1546, 2572, 2572, 1532, 1538, 1550,
-        0, 1550, 1550, 1550, 2573, 2573, 1537, 1540, 2575, 2575,
+     1546,    0, 1546, 1546, 1546, 2573, 2573, 1532, 1538, 1550,
+        0, 1550, 1550, 1550, 2576, 2576, 1537, 1540, 2588, 2588,
      1546, 1551, 1551, 1551, 1551, 1551, 1551,    0, 1562, 1550,
      1553, 1553, 1553, 1553, 1553, 1553, 1556, 1556, 1556, 1556,
      1556, 1556, 1558, 1558, 1558, 1558, 1558, 1558, 1562, 1565,
      1567, 1572, 1577, 1572, 1572, 1572, 1576, 1581, 1576, 1576,
      1576, 1579, 1583, 1579, 1579, 1580, 1585, 1580, 1580, 1565,
-     1567, 1572, 1577, 1586, 1586, 1586, 1576, 1581, 1587, 2576,
-     2576, 1579, 1583, 2587, 2587, 1580, 1585, 1588, 1586, 1588,
+     1567, 1572, 1577, 1586, 1586, 1586, 1576, 1581, 1587, 2591,
+     2591, 1579, 1583,    0,    0, 1580, 1585, 1588, 1586, 1588,
 
-     1588, 1589, 1594, 1589, 1589, 2588, 2588, 1590, 1587, 1590,
+     1588, 1589, 1594, 1589, 1589,    0,    0, 1590, 1587, 1590,
      1590, 1591,    0, 1591, 1591,    0, 1595, 1588, 1595, 1595,
-        0, 1589, 1594, 1596,    0, 1596, 1596, 1590, 2590, 2590,
+        0, 1589, 1594, 1596,    0, 1596, 1596, 1590,    0,    0,
      1597, 1591, 1597, 1597,    0, 1598, 1595, 1598, 1598, 1600,
         0, 1600, 1600, 1596, 1601,    0, 1601, 1601,    0, 1602,
      1597, 1602, 1602,    0, 1603, 1598, 1603, 1603, 1604, 1600,
@@ -3614,7 +3616,7 @@ static const flex_int16_t yy_chk[16782] =
      1608,    0, 1609, 1605, 1609, 1609,    0, 1610, 1606, 1610,
      1610,    0, 1611, 1607, 1611, 1611, 1612, 1608, 1612, 1612,
 
-        0, 1613, 1609, 1613, 1613, 2591, 2591, 1610,    0,    0,
+        0, 1613, 1609, 1613, 1613,    0,    0, 1610,    0,    0,
         0,    0, 1611,    0,    0,    0, 1612,    0,    0,    0,
         0, 1613, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615,
      1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615,
@@ -4806,55 +4808,57 @@ static const flex_int16_t yy_chk[16782] =
      2565,    0,    0,    0,    0, 2565, 2566, 2566, 2566, 2567,
         0,    0,    0, 2567, 2567, 2567,    0,    0,    0,    0,
      2567, 2568, 2568, 2568, 2569, 2569, 2569, 2570, 2570, 2570,
-     2571, 2571, 2571, 2574,    0, 2574,    0, 2574, 2574,    0,
-        0,    0,    0,    0, 2574, 2577,    0, 2577,    0, 2577,
-     2577,    0,    0,    0,    0,    0, 2577, 2578, 2578, 2578,
-     2579, 2579, 2579, 2580,    0,    0,    0, 2580, 2580, 2580,
-        0,    0,    0,    0, 2580, 2581, 2581, 2581, 2582,    0,
-        0,    0, 2582, 2582, 2582,    0,    0,    0,    0, 2582,
-
-     2583, 2583, 2583, 2584, 2584, 2584, 2585, 2585, 2585, 2586,
-     2586, 2586, 2589,    0, 2589,    0, 2589, 2589,    0,    0,
-        0,    0,    0, 2589, 2592,    0, 2592,    0, 2592, 2592,
-        0,    0,    0,    0,    0, 2592, 2593, 2593, 2593, 2594,
-        0,    0,    0, 2594, 2594, 2594,    0,    0,    0,    0,
-     2594, 2595, 2595, 2595, 2596, 2596, 2596, 2597, 2597, 2597,
-     2598, 2598, 2598, 2599, 2599, 2599, 2600, 2600, 2600, 2601,
-     2601, 2601, 2602, 2602, 2602, 2603, 2603, 2603, 2604, 2604,
-     2604, 2605, 2605, 2605, 2606, 2606, 2606, 2607, 2607, 2607,
-     2608,    0, 2608,    0, 2608, 2608, 2608,    0,    0,    0,
-
-        0, 2608, 2609,    0, 2609,    0, 2609, 2609, 2609,    0,
-        0,    0,    0, 2609, 2610, 2610, 2610, 2611, 2611, 2611,
-     2612,    0, 2612,    0, 2612, 2612, 2612,    0,    0,    0,
-        0, 2612, 2613,    0, 2613,    0, 2613, 2613, 2613,    0,
-        0,    0,    0, 2613, 2614,    0, 2614,    0, 2614, 2614,
-     2614,    0,    0,    0,    0, 2614, 2615,    0, 2615,    0,
-     2615, 2615, 2615,    0,    0,    0,    0, 2615, 2616, 2616,
-     2616, 2617,    0, 2617,    0, 2617, 2617, 2617,    0,    0,
-        0,    0, 2617, 2618,    0, 2618,    0, 2618, 2618, 2618,
-        0,    0,    0,    0, 2618, 2619,    0, 2619,    0, 2619,
-
-     2619, 2619,    0,    0,    0,    0, 2619, 2620,    0, 2620,
-        0, 2620, 2620, 2620,    0,    0,    0,    0, 2620, 2621,
-        0, 2621,    0, 2621, 2621, 2621,    0,    0,    0,    0,
-     2621, 2622,    0, 2622,    0, 2622, 2622, 2622,    0,    0,
-        0,    0, 2622, 2623,    0, 2623,    0, 2623, 2623, 2623,
-        0,    0,    0,    0, 2623, 2624,    0, 2624,    0, 2624,
-     2624, 2624,    0,    0,    0,    0, 2624, 2625,    0, 2625,
-        0, 2625, 2625, 2625,    0,    0,    0,    0, 2625, 2626,
-        0, 2626,    0, 2626, 2626, 2626,    0,    0,    0,    0,
-     2626, 2627,    0, 2627,    0, 2627, 2627, 2627,    0,    0,
-
-        0,    0, 2627, 2628,    0, 2628,    0, 2628, 2628, 2628,
-        0,    0,    0,    0, 2628, 2629,    0, 2629,    0, 2629,
-     2629, 2629,    0,    0,    0,    0, 2629, 2630,    0, 2630,
-        0, 2630, 2630, 2630,    0,    0,    0,    0, 2630, 1614,
+     2571, 2571, 2571, 2572, 2572, 2572, 2574,    0, 2574,    0,
+     2574, 2574,    0,    0,    0,    0,    0, 2574, 2575, 2575,
+     2575, 2577,    0, 2577,    0, 2577, 2577,    0,    0,    0,
+        0,    0, 2577, 2578, 2578, 2578, 2579, 2579, 2579, 2580,
+        0,    0,    0, 2580, 2580, 2580,    0,    0,    0,    0,
+     2580, 2581, 2581, 2581, 2582,    0,    0,    0, 2582, 2582,
+
+     2582,    0,    0,    0,    0, 2582, 2583, 2583, 2583, 2584,
+     2584, 2584, 2585, 2585, 2585, 2586, 2586, 2586, 2587, 2587,
+     2587, 2589,    0, 2589,    0, 2589, 2589,    0,    0,    0,
+        0,    0, 2589, 2590, 2590, 2590, 2592,    0, 2592,    0,
+     2592, 2592,    0,    0,    0,    0,    0, 2592, 2593, 2593,
+     2593, 2594,    0,    0,    0, 2594, 2594, 2594,    0,    0,
+        0,    0, 2594, 2595, 2595, 2595, 2596, 2596, 2596, 2597,
+     2597, 2597, 2598, 2598, 2598, 2599, 2599, 2599, 2600, 2600,
+     2600, 2601, 2601, 2601, 2602, 2602, 2602, 2603, 2603, 2603,
+     2604, 2604, 2604, 2605, 2605, 2605, 2606, 2606, 2606, 2607,
+
+     2607, 2607, 2608,    0, 2608,    0, 2608, 2608, 2608,    0,
+        0,    0,    0, 2608, 2609,    0, 2609,    0, 2609, 2609,
+     2609,    0,    0,    0,    0, 2609, 2610, 2610, 2610, 2611,
+     2611, 2611, 2612,    0, 2612,    0, 2612, 2612, 2612,    0,
+        0,    0,    0, 2612, 2613,    0, 2613,    0, 2613, 2613,
+     2613,    0,    0,    0,    0, 2613, 2614,    0, 2614,    0,
+     2614, 2614, 2614,    0,    0,    0,    0, 2614, 2615,    0,
+     2615,    0, 2615, 2615, 2615,    0,    0,    0,    0, 2615,
+     2616, 2616, 2616, 2617,    0, 2617,    0, 2617, 2617, 2617,
+        0,    0,    0,    0, 2617, 2618,    0, 2618,    0, 2618,
+
+     2618, 2618,    0,    0,    0,    0, 2618, 2619,    0, 2619,
+        0, 2619, 2619, 2619,    0,    0,    0,    0, 2619, 2620,
+        0, 2620,    0, 2620, 2620, 2620,    0,    0,    0,    0,
+     2620, 2621,    0, 2621,    0, 2621, 2621, 2621,    0,    0,
+        0,    0, 2621, 2622,    0, 2622,    0, 2622, 2622, 2622,
+        0,    0,    0,    0, 2622, 2623,    0, 2623,    0, 2623,
+     2623, 2623,    0,    0,    0,    0, 2623, 2624,    0, 2624,
+        0, 2624, 2624, 2624,    0,    0,    0,    0, 2624, 2625,
+        0, 2625,    0, 2625, 2625, 2625,    0,    0,    0,    0,
+     2625, 2626,    0, 2626,    0, 2626, 2626, 2626,    0,    0,
+
+        0,    0, 2626, 2627,    0, 2627,    0, 2627, 2627, 2627,
+        0,    0,    0,    0, 2627, 2628,    0, 2628,    0, 2628,
+     2628, 2628,    0,    0,    0,    0, 2628, 2629,    0, 2629,
+        0, 2629, 2629, 2629,    0,    0,    0,    0, 2629, 2630,
+        0, 2630,    0, 2630, 2630, 2630,    0,    0,    0,    0,
+     2630, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
      1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
-     1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1614,
-     1614
+     1614, 1614, 1614
+
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -4867,7 +4871,7 @@ static const flex_int16_t yy_chk[16782] =
 #line 1 "vrscanl.l"
 /*
  *
- *  Copyright (C) 1997-2022, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -4892,7 +4896,7 @@ static const flex_int16_t yy_chk[16782] =
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 #include "vrscani.h"
-#line 4896 "vrscanl.c"
+#line 4900 "vrscanl.c"
 /* Make this work on windows (we don't need interactivity anyway) */
 /* This seems to be a bug: The .c file won't include it, but .h will
  * nevertheless.
@@ -4900,7 +4904,7 @@ static const flex_int16_t yy_chk[16782] =
  * Our workaround: Define YY_NO_UNISTD_H in vrscani.h and make
  * sure that header is included before vrscanl.h.
  */
-#line 4904 "vrscanl.c"
+#line 4908 "vrscanl.c"
 
 #define INITIAL 0
 
@@ -5161,7 +5165,7 @@ YY_DECL
 #line 101 "vrscanl.l"
 
 
-#line 5165 "vrscanl.c"
+#line 5169 "vrscanl.c"
 
        while ( /*CONSTCOND*/1 )                /* loops until end-of-file is reached */
                {
@@ -5325,7 +5329,7 @@ YY_RULE_SETUP
 #line 126 "vrscanl.l"
 ECHO;
        YY_BREAK
-#line 5329 "vrscanl.c"
+#line 5333 "vrscanl.c"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
index 9d707e24391a34f59b4529384e1438fb497dc884..fa46c792a6d76935ef30f4d2e4d810ebcd3c0ea7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2022, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -44,7 +44,7 @@ charset_without_control_chars         [\040-\133\135-\176\240-\377\033]+
 charset_with_control_chars            [\040-\176\240-\377\011\012\014\015\033]+
 spaces                                [ ]*
 zero_byte_padding                     \000?
-dt_offset                             (\-1200)|(\+1400)|(((\-((0[1-9])|(1[0-1])))|(\+((0[1-9])|(1[0-3])))){tm_minute})
+dt_offset                             (\-1200)|(\+1400)|(((\-((0[1-9])|(1[0-1])))|(\+((0[0-9])|(1[0-3])))){tm_minute})
 da_year                               (18[5-9][0-9])|(19[0-9]{2})|(20[0-4][0-9])
 da_year_dub                           [0-9]{4}
 da_month                              (0[1-9])|(1[0-2])
index cae0ef8889c5f865711e548fc7485fd5c7495de8..98ea562ea7a71de310c6f1a79fdfa441e991cb20 100644 (file)
@@ -4,6 +4,7 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmdata_tests
   tchval.cc
   tdict.cc
   telemlen.cc
+  tfrmsiz.cc
   tests.cc
   tfilter.cc
   tgenuid.cc
@@ -33,7 +34,7 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmdata_tests
 )
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcmdata_tests i2d dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(dcmdata_tests i2d)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmdata)
index 6053caaf359b2cec95114bf86769661f7804ea4c..800b37b2e646b5a90695b1edbbd8db9634935c88 100644 (file)
@@ -420,6 +420,72 @@ tfilter.o: tfilter.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmdata/dclist.h ../include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmdata/dcitem.h ../include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmdata/dcdict.h ../include/dcmtk/dcmdata/dchashdi.h
+tfrmsiz.o: tfrmsiz.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdefine.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
+ ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
+ ../include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
+ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcpixseq.h \
+ ../include/dcmtk/dcmdata/dcsequen.h ../include/dcmtk/dcmdata/dcelem.h \
+ ../include/dcmtk/dcmdata/dcofsetl.h ../include/dcmtk/dcmdata/dcpxitem.h \
+ ../include/dcmtk/dcmdata/dcvrobow.h ../include/dcmtk/dcmdata/dcdeftag.h \
+ ../include/dcmtk/dcmdata/dcrlerp.h ../include/dcmtk/dcmdata/dcpixel.h \
+ ../include/dcmtk/dcmdata/dcvrpobw.h ../include/dcmtk/dcmdata/dcrledrg.h
 tgenuid.o: tgenuid.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/oftest.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
index c16b46f5c23d54f71bfd0139de469ca0ebbe119c..03312127821a67eadbcbcdbc46712d115dbd823a 100644 (file)
@@ -26,7 +26,7 @@ LIBDCMXML = -ldcmxml
 objs = tests.o tpread.o ti2dbmp.o tchval.o tpath.o tvrdatim.o telemlen.o tparser.o \
        tdict.o tvrds.o tvrfd.o tvrui.o tvrol.o tvrov.o tvrsv.o tvruv.o tstrval.o \
        tspchrs.o tvrpn.o tparent.o tfilter.o tvrcomp.o tmatch.o tnewdcme.o \
-       tgenuid.o tsequen.o titem.o ttag.o txfer.o tbytestr.o
+       tgenuid.o tsequen.o titem.o ttag.o txfer.o tbytestr.o tfrmsiz.o
 
 progs = tests
 
index e57c1f502f7be09ba367b596fa278537f6e9a3b5..5e07dd6e449ef92a4016f074c27e2dbb58955162 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2009-2016, OFFIS e.V.
+ *  Copyright (C) 2009-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -111,6 +111,17 @@ OFTEST(dcmdata_checkStringValue)
   CHECK_GOOD( "DT-15", DcmDateTime::checkStringValue("200907", "1") )
   CHECK_GOOD( "DT-16", DcmDateTime::checkStringValue("2009", "1") )
   CHECK_BAD ( "DT-17", DcmDateTime::checkStringValue("20091", "1") )
+  /* check various timezone values, both valid and invalid ones */
+  CHECK_GOOD( "DT-18", DcmDateTime::checkStringValue("202501011200+0000"));
+  CHECK_BAD ( "DT-19", DcmDateTime::checkStringValue("202501011200-0000"));
+  CHECK_GOOD( "DT-20", DcmDateTime::checkStringValue("202501011200+0100"));
+  CHECK_GOOD( "DT-21", DcmDateTime::checkStringValue("202412311200-1130"));
+  CHECK_GOOD( "DT-22", DcmDateTime::checkStringValue("202412311200-1200"));
+  CHECK_BAD ( "DT-23", DcmDateTime::checkStringValue("202412311200-1230"));
+  CHECK_GOOD( "DT-24", DcmDateTime::checkStringValue("202412311200+1200"));
+  CHECK_GOOD( "DT-25", DcmDateTime::checkStringValue("202412311200+1330"));
+  CHECK_GOOD( "DT-26", DcmDateTime::checkStringValue("202412311200+1400"));
+  CHECK_BAD ( "DT-27", DcmDateTime::checkStringValue("202412311200+1430"));
 
   /* test "Decimal String" */
   CHECK_GOOD( "DS-01", DcmDecimalString::checkStringValue(" 0", "1") )
@@ -154,8 +165,9 @@ OFTEST(dcmdata_checkStringValue)
 // maximum length cannot be checked if given in characters (and not bytes)
 //  CHECK_BAD ( "LO-07", DcmLongString::checkStringValueu("OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany, http://www.offis.de/", "1") )
   CHECK_GOOD( "LO-08", DcmLongString::checkStringValue("\\ _2_ \\ _3_ \\ _4_ \\ _5_ \\", "6") )
-  CHECK_GOOD( "LO-09", DcmLongString::checkStringValue("ESC\033aping", "1") )
-  CHECK_BAD ( "LO-10", DcmLongString::checkStringValue("not allowed: \r\014", "1") )
+  // actually, the following test should fail
+  CHECK_GOOD( "LO-09", DcmLongString::checkStringValue("ESC only allowed for ISO 2022 character set control sequences: \033", "1") )
+  CHECK_BAD ( "LO-10", DcmLongString::checkStringValue("also not allowed: \r\014", "1") )
 
   /* test "Long Text" */
   CHECK_GOOD( "LT-01", DcmLongText::checkStringValue(" Hello \\ 12345 \\ \344\366\374\337 ", "ISO_IR 100") )
@@ -203,8 +215,10 @@ OFTEST(dcmdata_checkStringValue)
   CHECK_GOOD( "SH-08", DcmShortString::checkStringValue("\\ _2_ \\ _3_ \\ _4_ \\ _5_ \\", "6") )
   CHECK_BAD ( "SH-09", DcmShortString::checkStringValue(" ", "2") )
   CHECK_GOOD( "SH-10", DcmShortString::checkStringValue("", "2") )
-  CHECK_GOOD( "SH-11", DcmShortString::checkStringValue("ESC\033aping", "1") )
-  CHECK_BAD ( "SH-12", DcmShortString::checkStringValue("not allowed: \n\010\r\014", "1") )
+  // actually, the following test should fail
+  CHECK_GOOD( "SH-11", DcmShortString::checkStringValue("not allowed: \033", "1") )
+  CHECK_BAD ( "SH-12", DcmShortString::checkStringValue("not allowed: \n\r", "1") )
+  CHECK_BAD ( "SH-13", DcmShortString::checkStringValue("not allowed: \010\014", "1") )
 
   /* test "Short Text" */
   CHECK_GOOD( "ST-01", DcmShortText::checkStringValue(" umlaut characters are allowed: \304\326\334\344\366\374\naccented characters also: \341\340\351\350\355\354\342\352\364\rand control characters, of course, including \033=ESC ", "ISO_IR 100") )
index 1a14365a203cc4369e43413da5ecda413e23164b..c8b40d42150e760a28b67177f71968eddb0bb9be 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2024 OFFIS e.V.
+ *  Copyright (C) 2011-2025 OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -126,4 +126,6 @@ OFTEST_REGISTER(dcmdata_xferLookup_2);
 OFTEST_REGISTER(dcmdata_xferLookup_3);
 OFTEST_REGISTER(dcmdata_xferLookup_4);
 OFTEST_REGISTER(dcmdata_putOFStringAtPos);
+OFTEST_REGISTER(dcmdata_uncompressedFrameSize);
+
 OFTEST_MAIN("dcmdata")
index b1cbbea4a934676a2bc664b62cdaf7a0b2de7736..cd60ec84b1e2b3d1a11eac89bc2f70ec7f0668e2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2020, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -49,7 +49,6 @@ OFTEST( dcmdata_attribute_filter )
     // test anonymous filter object
     OFCHECK( DcmAttributeFilter( DCM_SOPClassUID, UID_ComputedRadiographyImageStorage )( item ) );
 
-#if !defined(_MSC_VER) || _MSC_VER > 1200 // iterator based filters not supported for VS <= 6.0.
     // test iterator (array) based range
     const char* filter_range[3] =
     {
@@ -80,7 +79,5 @@ OFTEST( dcmdata_attribute_filter )
     OFCHECK( ct_mr_filter( item ) );
     item.putAndInsertString( DCM_SOPClassUID, UID_EnhancedCTImageStorage );
     OFCHECK( !cr_ct_mr_filter( item ) );
-#endif
-
     OFCHECK( DcmAttributeFilter()( item ) ); // test default constructed (allow any) filter.
 }
diff --git a/dcmdata/tests/tfrmsiz.cc b/dcmdata/tests/tfrmsiz.cc
new file mode 100644 (file)
index 0000000..10b0329
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmdata
+ *
+ *  Author:  Marco Eichelberg
+ *
+ *  Purpose: test program for DcmElement::getUncompressedFrameSize()
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/dcmdata/dcdatset.h"
+#include "dcmtk/dcmdata/dcpixseq.h"
+#include "dcmtk/dcmdata/dcpxitem.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dcrlerp.h"
+#include "dcmtk/dcmdata/dcrledrg.h"
+
+OFTEST(dcmdata_uncompressedFrameSize)
+{
+    // prepare an uncompressed dataset with the attributes we need for this test
+    DcmDataset dset;
+    OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 8).good());
+    OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 8).good());
+    OFCHECK(dset.putAndInsertUint16(DCM_HighBit, 7).good());
+    OFCHECK(dset.putAndInsertUint16(DCM_Columns, 256).good());
+    OFCHECK(dset.putAndInsertUint16(DCM_Rows, 256).good());
+    OFCHECK(dset.putAndInsertUint16(DCM_SamplesPerPixel, 3).good());
+    OFCHECK(dset.putAndInsertString(DCM_PhotometricInterpretation, "RGB").good());
+
+    // create and insert an empty pixel data element
+    DcmPixelData *px = NULL;
+    OFCHECK(NULL != (px = new DcmPixelData(DCM_PixelData)));
+    if (px)
+    {
+        OFCHECK(dset.insert(px).good());
+
+        // Tests for DcmElement::decodedBitsAllocated() with uncompressed pixel data.
+        // This should always return the first parameter (BitsAllocated), unless the
+        // second parameter (BitsStored) is larger than the first one, in which case
+        // the result should be zero.
+        OFCHECK(0 == px->decodedBitsAllocated(8, 9));
+        OFCHECK(5 == px->decodedBitsAllocated(5, 1));
+        OFCHECK(7 == px->decodedBitsAllocated(7, 1));
+        OFCHECK(8 == px->decodedBitsAllocated(8, 8));
+        OFCHECK(9 == px->decodedBitsAllocated(9, 8));
+        OFCHECK(13 == px->decodedBitsAllocated(13, 8));
+        OFCHECK(23 == px->decodedBitsAllocated(23, 8));
+        OFCHECK(255 == px->decodedBitsAllocated(255, 8));
+
+        // Tests for getUncompressedFrameSize() with an uncompressed dataset
+        Uint32 frameSize = 0;
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(196608 == frameSize);
+
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 12).good());
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 12).good());
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(294912 == frameSize);
+
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 16).good());
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 12).good());
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(393216 == frameSize);
+
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 32).good());
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 32).good());
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(786432 == frameSize);
+
+        // set color model to YBR_FULL_422 and create a frame size indicating that we have in fact RGB
+        Uint16 *pxdata = NULL;
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 8).good());
+        OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 8).good());
+        OFCHECK(dset.putAndInsertString(DCM_PhotometricInterpretation, "YBR_FULL_422").good());
+        OFCHECK(px->createUint16Array(98304, pxdata).good());
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(196608 == frameSize);
+
+        // set color model to YBR_FULL_422 and create a frame size indicating that we have in fact uncompressed YBR_FULL_422
+        OFCHECK(px->createUint16Array(65536, pxdata).good());
+        OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+        OFCHECK(131072 == frameSize);
+
+        // now convert the dataset to an RLE compressed one and check again
+        OFCHECK(dset.putAndInsertString(DCM_PhotometricInterpretation, "RGB").good());
+        DcmRLERepresentationParameter rle_rp;
+        DcmPixelSequence *pixelSequence = new DcmPixelSequence(DCM_PixelSequenceTag);
+        DcmPixelItem *offsetTable = new DcmPixelItem(DCM_PixelItemTag);
+        OFCHECK((NULL != pixelSequence) && (NULL != offsetTable));
+        if (pixelSequence && offsetTable)
+        {
+            pixelSequence->insert(offsetTable);
+            px->putOriginalRepresentation(EXS_RLELossless, &rle_rp, pixelSequence);
+
+            // this should fail because the RLE decoder is not registered yet,
+            // and, therefore, the computation of the uncompressed frame size will fail
+            OFCHECK(EC_InvalidValue == px->getUncompressedFrameSize(&dset, frameSize, OFTrue));
+
+            // register RLE decompression codec
+            DcmRLEDecoderRegistration::registerCodecs();
+
+            // now we can compute the frame size for the RLE compressed image
+            OFCHECK(px->getUncompressedFrameSize(&dset, frameSize, OFTrue).good());
+            OFCHECK(196608 == frameSize);
+
+            // the RLE codec should refuse the size calculation if BitsAllocated is not a multiple of 8
+            OFCHECK(dset.putAndInsertUint16(DCM_BitsAllocated, 12).good());
+            OFCHECK(dset.putAndInsertUint16(DCM_BitsStored, 12).good());
+            OFCHECK(EC_InvalidValue == px->getUncompressedFrameSize(&dset, frameSize, OFTrue));
+
+            // these calls should now invoke the routine in the RLE codec that computes
+            // decoded bits allocated.
+            OFCHECK(0 == px->decodedBitsAllocated(8, 9));
+            OFCHECK(0 == px->decodedBitsAllocated(5, 1));
+            OFCHECK(8 == px->decodedBitsAllocated(8, 8));
+            OFCHECK(0 == px->decodedBitsAllocated(13, 8));
+            OFCHECK(16 == px->decodedBitsAllocated(16, 8));
+            OFCHECK(64 == px->decodedBitsAllocated(64, 8));
+
+            // avoid memory leak
+            DcmRLEDecoderRegistration::cleanup();
+        }
+    }
+}
index 3a6959ba96d7465f5f5fa1038fcb754dabb91b79..c8d2b9e8ba5d11a39c943017859ba0ffd2be2614 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2019-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -40,19 +40,29 @@ OFTEST(dcmdata_sequenceInsert)
     DcmSequenceOfItems sequence(DCM_OtherPatientIDsSequence);
     /* add a large number of items to the sequence */
     unsigned long counter = 0;
+    DcmItem *items[NUMBER_OF_ITEMS];
     for (unsigned long i = 0; i < NUMBER_OF_ITEMS; ++i)
     {
-        if (sequence.insert(new DcmItem()).good())
+        items[i] = new DcmItem();
+        if (sequence.insert(items[i]).good())
             ++counter;
     }
     /* check whether that worked (for-loop shouldn't take too long) */
     OFCHECK_EQUAL(counter, NUMBER_OF_ITEMS);
     /* access specific items (performance should be no issue) */
-    OFCHECK(sequence.getItem(0) != NULL);
-    OFCHECK(sequence.getItem(2) != NULL);
+    OFCHECK(sequence.getItem(0) == items[0]);
+    OFCHECK(sequence.getItem(2) == items[2]);
     OFCHECK(sequence.getItem(NUMBER_OF_ITEMS) == NULL);
-    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 1) != NULL);
-    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 2) != NULL);
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 1) == items[NUMBER_OF_ITEMS - 1]);
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 2) == items[NUMBER_OF_ITEMS - 2]);
+    /* insert a single item before the current item */
+    DcmItem *newItem = new DcmItem();
+    OFCHECK(sequence.insertAtCurrentPos(newItem, OFTrue /*before*/).good());
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 2) == newItem);
+    /* the items after the new item should have been shifted by one */
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS - 1) == items[NUMBER_OF_ITEMS - 2]);
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS) == items[NUMBER_OF_ITEMS - 1]);
+    OFCHECK(sequence.getItem(NUMBER_OF_ITEMS + 1) == NULL);
 }
 
 
index 2f90bf5fef4b6b2a4d23cf2bdf69c0b11691e2f0..db00f1b998585400aa056a4962cafe60d8be71c0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2020, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
index 3a4c39fae89f6ff6706360e2baa4716d1c0c812c..9745fad1a996776d4f2ffb0757229c2224c7de18 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -204,6 +204,16 @@ public:
      */
     virtual OFBool getCheckFGOnWrite();
 
+    /** Set whether attribute values should be checked on writing, i.e. if writing
+     *  should fail if attribute values violate their VR, VM, character set or value length.
+     *  A missing but required value is always considered an error, independent of this setting.
+     *  If set to OFFalse, writing will always succeed, even if attribute value constraints
+     *  are violated. A warning instead of an error will be printed to the logger.
+     *  @param  doCheck If OFTrue, attribute value errors are handled as errors on writing, if OFFalse
+     *          any errors are ignored.
+     */
+    virtual void setValueCheckOnWrite(const OFBool doCheck);
+
     // -------------------- creation ---------------------
 
     /** Factory method to create an Enhanced CT object from the minimal
@@ -739,7 +749,7 @@ private:
     IODCommonInstanceReferenceModule m_CommonInstanceReferenceModule;
 
     /// Binary frame data
-    OFVector<DcmIODTypes::Frame*> m_Frames;
+    OFVector<DcmIODTypes::FrameBase*> m_Frames;
 
     /// Multi-frame Functional Groups high level interface
     FGInterface m_FGInterface;
index 7f2cabeaed55c83efb2993b2a21e31b86199f8cb..3ff3d9ebc104e9999142e0abe9fa4ae29f985e01 100644 (file)
@@ -70,6 +70,7 @@ enhanced_ct.o: enhanced_ct.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
index 46e0aa685f2c303fb532b35c85b16ca6610a3c0a..527cc10605e109f69dde29c22a2ca8e884001fa6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -110,7 +110,7 @@ struct EctEnhancedCT::WriteVisitor
             return FG_EC_PixelDataTooLarge;
         }
         const size_t numPixelsFrame = OFstatic_cast(size_t, rows) * OFstatic_cast(size_t, cols);
-        const size_t numBytesFrame  = m_CT.m_Frames[0]->length;
+        const size_t numBytesFrame  = m_CT.m_Frames[0]->getLengthInBytes();
         if (numBytesFrame != numPixelsFrame * 2)
         {
             DCMECT_ERROR("Invalid number of bytes per frame: Expected " << numPixelsFrame * 2 << " but got "
@@ -124,16 +124,16 @@ struct EctEnhancedCT::WriteVisitor
         {
             pixData->setVR(EVR_OW);
             Uint16* ptr          = NULL;
-            size_t numBytesTotal = numBytesFrame * numFrames / 2;
+            size_t numBytesTotal = numBytesFrame * numFrames;
             if (numBytesTotal <= 4294967294UL)
             {
-                result = pixData->createUint16Array(OFstatic_cast(Uint32, numBytesTotal), ptr);
+                result = pixData->createUint16Array(OFstatic_cast(Uint32, numBytesTotal / 2), ptr);
                 // copy all frames into CT's frame structure
                 if (ptr)
                 {
                     for (size_t f = 0; f < numFrames; ++f)
                     {
-                        memcpy(ptr, m_CT.m_Frames[f]->pixData, numBytesFrame);
+                        memcpy(ptr, m_CT.m_Frames[f]->getPixelData(), numBytesFrame);
                         ptr += numPixelsFrame;
                     }
                     return m_Item.insert(pixData);
@@ -160,7 +160,7 @@ struct EctEnhancedCT::WriteVisitorConcatenation
     // Inner class that implements the writing to Concatentions via ConcatenationCreator class
 
     // Constructor, sets parameters the visitor works on in operator()
-    WriteVisitorConcatenation(EctEnhancedCT& m, Uint8*& pixData, size_t& pixDataLength)
+    WriteVisitorConcatenation(EctEnhancedCT& m, Uint16*& pixData, size_t& pixDataLength)
         : m_CT(m)
         , m_pixData(pixData)
         , m_pixDataLength(pixDataLength)
@@ -186,20 +186,20 @@ struct EctEnhancedCT::WriteVisitorConcatenation
         m_CT.getRows(rows);
         m_CT.getColumns(cols);
         const size_t numFrames     = m_CT.m_Frames.size();
-        const size_t numBytesFrame = m_CT.m_Frames[0]->length;
+        const size_t numBytesFrame = m_CT.m_Frames[0]->getLengthInBytes();
         // Creates the correct pixel data element, based on the image pixel module used.
         m_pixDataLength = numBytesFrame * numFrames;
-        m_pixData       = new Uint8[m_pixDataLength];
+        m_pixData       = new Uint16[m_pixDataLength / 2];
         if (m_pixData)
         {
-            Uint8* ptr = m_pixData;
+            Uint16* ptr = m_pixData;
             // copy all frames into CT's frame structure
             if (ptr)
             {
                 for (size_t f = 0; f < numFrames; ++f)
                 {
-                    memcpy(ptr, m_CT.m_Frames[f]->pixData, numBytesFrame);
-                    ptr += numBytesFrame;
+                    memcpy(ptr, m_CT.m_Frames[f]->getPixelData(), numBytesFrame);
+                    ptr += numBytesFrame / 2;
                 }
                 return EC_Normal;
             }
@@ -211,7 +211,7 @@ struct EctEnhancedCT::WriteVisitorConcatenation
 
     // Members, i.e. parameters to operator()
     EctEnhancedCT& m_CT;
-    Uint8*& m_pixData;
+    Uint16*& m_pixData;
     size_t& m_pixDataLength;
 };
 
@@ -276,12 +276,10 @@ struct EctEnhancedCT::ReadVisitor
             {
                 for (Uint32 n = 0; n < numFrames; n++)
                 {
-                    DcmIODTypes::Frame* f = new DcmIODTypes::Frame;
+                    DcmIODTypes::Frame<Uint16>* f = new DcmIODTypes::Frame<Uint16>(numBytesFrame / 2);
                     if (f)
                     {
-                        f->length  = numBytesFrame;
-                        f->pixData = new Uint8[f->length];
-                        memcpy(f->pixData, pixData + n * numBytesFrame / 2, numBytesFrame);
+                        memcpy(f->m_pixData, pixData + n * numBytesFrame / 2, numBytesFrame);
                         m_CT.m_Frames.push_back(f);
                     }
                     else
@@ -328,12 +326,10 @@ OFCondition EctEnhancedCT::Frames<PixelType>::addFrame(PixelType* data,
     {
         if (!perFrameInformation.empty())
         {
-            OFunique_ptr<DcmIODTypes::Frame> f(new DcmIODTypes::Frame);
+            OFunique_ptr<DcmIODTypes::Frame<Uint16> > f(new DcmIODTypes::Frame<Uint16>(numPixels));
             if (f)
             {
-                f->length  = numPixels * sizeof(PixelType);
-                f->pixData = new Uint8[f->length];
-                memcpy(f->pixData, data, f->length);
+                memcpy(f->m_pixData, data, f->getLengthInBytes());
                 m_CT.m_Frames.push_back(f.release());
                 OFVector<FGBase*>::const_iterator fg = perFrameInformation.begin();
                 while (result.good() && (fg != perFrameInformation.end()))
@@ -361,14 +357,15 @@ PixelType* EctEnhancedCT::Frames<PixelType>::getFrame(const size_t frameNumber)
 {
     if (frameNumber < m_CT.m_Frames.size())
     {
-        return (PixelType*)(m_CT.m_Frames[frameNumber]->pixData);
+        DcmIODTypes::Frame<PixelType>* f = OFstatic_cast(DcmIODTypes::Frame<PixelType>*, m_CT.m_Frames[frameNumber]);
+        return f->getPixelDataTyped();
     }
     return NULL;
 }
 
 // Helper "class" that returns Frames offering API to the pixel's frame bulk
 // data by offering the dedicated data type, e.g. Float32 instead of the
-// internally stored generic Uint8 array.
+// internally stored generic Uint16 array.
 //
 struct EctEnhancedCT::GetFramesVisitor
 {
@@ -514,7 +511,7 @@ EctEnhancedCT::loadConcatenation(ConcatenationLoader& cl, const OFString& concat
 
     DcmDataset dset;
     ct = NULL;
-    OFVector<DcmIODTypes::Frame*> frames;
+    OFVector<DcmIODTypes::FrameBase*> frames;
     OFCondition result = cl.load(concatenationUID, &dset, frames);
     if (result.good())
     {
@@ -577,6 +574,17 @@ OFBool EctEnhancedCT::getCheckFGOnWrite()
     return m_FGInterface.getCheckOnWrite();
 }
 
+void EctEnhancedCT::setValueCheckOnWrite(const OFBool doCheck)
+{
+    m_SynchronizationModule.setValueCheckOnWrite(doCheck);
+    m_EnhancedGeneralEquipmentModule.setValueCheckOnWrite(doCheck);
+    m_FG.setValueCheckOnWrite(doCheck);
+    m_DimensionModule.setValueCheckOnWrite(doCheck);
+    m_AcquisitionContextModule.setValueCheckOnWrite(doCheck);
+    m_CommonInstanceReferenceModule.setValueCheckOnWrite(doCheck);
+    DcmIODImage::setValueCheckOnWrite(doCheck);
+}
+
 // ------------------ Creation -----------------------
 
 OFCondition EctEnhancedCT::create(EctEnhancedCT*& ct,
@@ -1051,6 +1059,7 @@ OFCondition EctEnhancedCT::setVolumeBasedCalculationTechnique(const OFString& va
     return result;
 }
 
+
 // -------------------- Protected Helpers --------------------------
 
 OFCondition EctEnhancedCT::read(DcmItem& dataset)
@@ -1083,7 +1092,7 @@ OFCondition EctEnhancedCT::writeConcatenation(ConcatenationCreator& cc)
     if (!item)
         return EC_MemoryExhausted;
 
-    Uint8* pixData       = NULL;
+    Uint16* pixData       = NULL;
     size_t pixDataLength = 0;
 
     OFCondition result
@@ -1190,7 +1199,15 @@ OFCondition EctEnhancedCT::readGeneric(DcmItem& dataset)
     }
 
     IODImage::read(dataset);
-    m_SynchronizationModule.read(dataset);
+    if (m_SynchronizationModuleEnabled)
+    {
+        // Synchronization Module is type C ("Required if time synchronization was​ applied"),
+        // so we make it optional for reading to avoid warnings on the attributes, and then reset rules
+        // to the default state.
+        m_SynchronizationModule.makeOptional();
+        m_SynchronizationModule.read(dataset);
+        m_SynchronizationModule.resetRules();
+    }
     m_EnhancedGeneralEquipmentModule.read(dataset);
     m_FG.read(dataset);
     m_DimensionModule.read(dataset);
index 89f73c38646ba81ff0795c5338f2fe5e4caebe6a..97c69cb4a61655c49284dfee58bd495e28d26bb5 100644 (file)
@@ -7,7 +7,7 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmect_tests
 )
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcmect_tests dcmect dcmfg dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(dcmect_tests dcmect dcmfg)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmect)
index acafe2c06d58d439a8f1e67c69dd7df5df098835..7cc0be3ca83e7b6d5f53aeccc76ae80b46c6ad59 100644 (file)
@@ -86,6 +86,7 @@ t_huge_concat.o: t_huge_concat.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -219,6 +220,7 @@ t_overflow.o: t_overflow.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -374,6 +376,7 @@ t_roundtrip.o: t_roundtrip.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
index 686552de3811bf0e019fdc66de25b193709606ca..d83a4684a2560ee5149509bcfa2f0193fd6ac69f 100644 (file)
@@ -60,7 +60,7 @@ static const Uint16 NUM_ROWS = 4000;
 // Number of Columns of image, might be changed for testing purposes
 static const Uint16 NUM_COLS = 4000;
 // Number of Frames of source image, might be changed for testing purposes
-static const Uint16 NUM_FRAMES = 200;
+static const Uint16 NUM_FRAMES = 100;
 // Number of Frames of in concatenation images, should not be changed since the
 // dumped checked against will assume Number of Frames = 1
 static const size_t NUM_FRAMES_CONCAT    = 1;
@@ -592,6 +592,8 @@ void loadAndCheckConcatenation(const OFList<OFFilename>& concats)
         DcmDataset merged;
         EctEnhancedCT* mergedCT = NULL;
         result                  = EctEnhancedCT::loadConcatenation(cl, cl.getInfo().begin()->first, mergedCT);
+        DcmItem item;
+        mergedCT->writeDataset(item);
         if (result.good())
         {
             ConcatenationCreator cc;
index 4e07a5c54bcc0eedb9e9c26f9456a9830b473b53..18dfc67d1494a95d1803222085a2aac1bc2fbaea 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2024, OFFIS e.V.
+ *  Copyright (C) 2024-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -85,8 +85,9 @@ OFTEST(dcmect_overflow)
 
     OFTempFile tf(O_RDWR, "", "t_overflow", ".dcm");
     OFCondition result;
-    result = ct->saveFile("output.dcm", EXS_LittleEndianExplicit);
+    result = ct->saveFile(tf.getFilename(), EXS_LittleEndianExplicit);
     OFCHECK_MSG(result == ECT_InvalidPixelInfo, result.text());
+    delete ct;
 }
 
 static EctEnhancedCT *create()
index a247fd5b675fb129bb455ec29203ec41f0c992e8..c78ff878d298bb51296be5c36d844769566aa706 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -27,6 +27,7 @@
 #include "dcmtk/ofstd/ofcond.h"
 #include "dcmtk/ofstd/offile.h"
 #include "dcmtk/dcmfg/fgdefine.h"
+#include "dcmtk/dcmiod/iodtypes.h"
 
 class DcmItem;
 class DcmSequenceOfItems;
@@ -89,6 +90,19 @@ public:
     virtual OFCondition
     setCfgInput(DcmItem* srcDataset, Uint8* pixelData, size_t pixelDataLength, OFBool transferOwnership);
 
+    /** Set input dataset with separate pixel data that should be split
+     *  into a number of concatenation instances.
+     *  @param  srcDataset The dataset to read from (must not be NULL and not contain
+     *          the Pixel Data attribute (on main level)
+     *  @param  pixelData Raw buffer of source pixel data
+     *  @param  pixelDataLength Length of pixelData buffer in bytes
+     *  @param  transferOwnership If OFTrue, the ConcatenationCreator class will
+     *          free memory of the srcDataset and pixelData after processing.
+     *  @return EC_Normal if input is considered valid (up to now), error otherwise
+     */
+    virtual OFCondition
+    setCfgInput(DcmItem* srcDataset, Uint16* pixelData, size_t pixelDataLength, OFBool transferOwnership);
+
     /** Set number of frames that should go into a single concatenation instance produced.
      *  The last concatenation instance might have less frames. This setting also
      *  directly determines the number of instances produced for a specific input.
@@ -180,6 +194,15 @@ protected:
      */
     virtual OFCondition configureCommon();
 
+    /** Prepare source pixel data (m_srcPixelData) according to the pixel data
+    *   existing in the source dataset.
+     *  @param  srcDataset The source dataset to read from
+     *  @param  transferOwnership If OFTrue, this class (m_srcPixelData)
+     *    takes ownership of the pixel data, i.e. frees memory on destruction.
+     *  @return EC_Normal if successful, error otherwise
+     */
+    virtual OFCondition initSrcPixelData(DcmItem* srcDataset, OFBool transferOwnership);
+
 private:
 
     /// Maximum number of instances that make up a Concatenation (=2^16-1=65535),
@@ -220,7 +243,7 @@ private:
     /// before the call to this class returns).
     /// Once the ConcatenationCreator creator class goes out of scope or reset() is being called,
     /// it is set to NULL. If m_cfgTransferOwnership is OFTrue, memory is freed by this class, too.
-    Uint8* m_srcPixelData;
+    DcmIODTypes::FrameBase* m_srcPixelData;
 
     /// VR of pixel data extracted/derived from source dataset. EVR_OB and EVR_OW are supported.
     /// Initially set to EVR_Unknown.
index ecd7f308eadbab188f26be1187e3563b9fb0e7e8..a9b3c5a679e1db5b697f17b6726d0b97a1fda84c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -48,6 +48,7 @@ class DcmItem;
  *  and a vector containing all frames of the merged instance.</li>
  * </ul>
  */
+
 class DCMTK_DCMFG_EXPORT ConcatenationLoader
 {
 
@@ -239,7 +240,7 @@ public:
      *  @return EC_Normal if loading Concatenation worked, error otherwise.
      */
     virtual OFCondition
-    load(const OFString& concatenationUID, DcmDataset* dataset, OFVector<DcmIODTypes::Frame*>& frames);
+    load(const OFString& concatenationUID, DcmDataset* dataset, OFVector<DcmIODTypes::FrameBase*>& frames);
 
 protected:
     /** Handles single file of a Concatenation and extracts structure for later
@@ -338,6 +339,13 @@ protected:
      */
     virtual OFCondition insertDestinationAttributes();
 
+    /** Compute bytes per frame based on Rows, Columns and Bits Allocated.
+     *  @param  rows The number of Rows
+     *  @param  cols The number of Columns
+     *  @param  bitsAlloc The Bits Allocated value (only 1, 8 or 16 supported)
+     *  @param  bytes_per_frame The resulting number of bytes per frame
+     *  @return EC_Normal if successful, error otherwise.
+     */
     virtual OFCondition
     computeBytesPerFrame(const Uint16 rows, const Uint16 cols, const Uint16 bitsAlloc, size_t& bytes_per_frame);
 
@@ -364,7 +372,7 @@ private:
     /// produced by the load() method. Once a merged instance is provided to
     /// the caller, as a result of load(), the caller is responsible for
     /// deleting the related memory.
-    OFVector<DcmIODTypes::Frame*> m_Frames;
+    OFVector<DcmIODTypes::FrameBase*> m_Frames;
 };
 
 #endif // CONCATENATIONLOADER_H
index 3ec373820479b9ff393bb51e4a317a24d6cef633..54a50b8e2ee6a4d0da70ee702b2d53c29f37551a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -57,6 +57,11 @@ public:
      */
     virtual void clear();
 
+    /** Get the number of functional groups in the set
+     *  @return Number of functional groups in the set
+     */
+    virtual size_t size() const;
+
     /** Find a functional group by its type
      *  @param  fgType The type of the functional group
      *  @return The functional group, if found, NULL otherwise
index a8c3b139bf0680b2eecaac97efd4334fe8ee554a..588cc7c1333f1e4153d62ec3fa981e14b849475e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -24,7 +24,7 @@
 
 #include "dcmtk/config/osconfig.h"
 
-#include "dcmtk/dcmdata/dcdatset.h"
+#include "dcmtk/dcmdata/dcvrcs.h"
 #include "dcmtk/dcmfg/fgbase.h"
 #include "dcmtk/dcmiod/iodmacro.h"
 #include "dcmtk/ofstd/ofstring.h"
@@ -66,6 +66,20 @@ public:
      */
     virtual ImageSOPInstanceReferenceMacro& getImageSOPInstanceReference();
 
+    /** Get Spatial Locations Preserved
+     *  @param  value Reference to variable in which the value should be stored
+     *  @param  pos Index of the value to get (0..vm-1), -1 for all components
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSpatialLocationsPreserved(OFString& value, const signed long pos = 0) const;
+
+    /** Set Spatial Locations Preserved
+     *  @param  value Value to be set (single value only) or "" for no value
+     *  @param  checkValue Check 'value' for conformance with VR (CS) and VM (1) if enabled
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition setSpatialLocationsPreserved(const OFString& value, const OFBool checkValue);
+
     /** Reads source image item from given item
      *  @param  itemOfSourceImageSequence Reference to item of Source Image Sequence
      *  @param  clearOldData If OFTue, old data in this class is cleared before reading
@@ -118,6 +132,9 @@ private:
     /// Contains the referenced images (as represented by one of the items of
     /// "this" Source Image Sequence)
     ImageSOPInstanceReferenceMacro m_ImageSOPInstanceReference;
+
+    /// Denotes whether spatial locations from source image have been preseved
+    DcmCodeString m_SpatialLocationsPreserved;
 };
 
 /// Iterator for traversing over items of the Source Image Sequence
index c046cfc9a1dccf3f3b2e955c4bfd6b9a9a440bb7..00f48a743d705976312396e43c81b5992273f2e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -40,6 +40,7 @@ class DCMTK_DCMFG_EXPORT FGInterface
 {
 
 public:
+
     /// Type representing per-frame functional groups, i.e.\ a number of
     /// functional groups assigned to each frame
     typedef OFMap<Uint32, FunctionalGroups*> PerFrameGroups;
@@ -201,6 +202,20 @@ public:
      */
     virtual OFBool getCheckOnWrite();
 
+    /** Sets the maximum number of threads to be used for reading and writing per-frame functional groups.
+     *  @param  numThreads The maximum number of threads to use
+     *    The number of threads will be adjusted to the number of frames, i.e.\ there will
+     *    be no more threads used than one fifth the number of frames (so that each thread must at least handle
+     *    10 frames, since otherwise the overhead of starting threads would be too high). The
+     *    number is adjusted on the fly.
+     */
+    virtual void setUseThreads(const Uint32 numThreads);
+
+    /** Returns the number of threads to be used for writing per-frame functional groups.
+     *  @return The number of threads to use
+     */
+    virtual Uint32 getUseThreads() const;
+
 protected:
     /** Get shared functional group based on its type
      *  @param  fgType The type of functional group
@@ -254,12 +269,16 @@ protected:
      */
     virtual OFCondition readPerFrameFG(DcmItem& dataset);
 
+    virtual OFCondition readPerFrameFGParallel(DcmSequenceOfItems& perFrameFGSeq, const Uint32 numThreads);
+
+    virtual OFCondition readPerFrameFGSequential(DcmSequenceOfItems& perFrameFGSeq);
+
     /** Read single functional group into the item provided
      *  @param  fgItem The item to read from
      *  @param  groups The resulting group after reading
      *  @return EC_Normal if reading was successful, error otherwise
      */
-    virtual OFCondition readSingleFG(DcmItem& fgItem, FunctionalGroups& groups);
+    static OFCondition readSingleFG(DcmItem& fgItem, FunctionalGroups& groups);
 
     /** Write Shared Functional Group Sequence to given item
      *  @param  dataset The item to write to
@@ -273,9 +292,23 @@ protected:
      */
     virtual OFCondition writePerFrameFG(DcmItem& dataset);
 
+    /** Write Per-Frame Functional Group Sequence to given item in parallel
+     *  @param  dataset The item to write to
+     *  @param  numThreads The maximum number of threads to use
+     *  @return EC_Normal if writing was successful, error otherwise
+     */
+    virtual OFCondition writePerFrameFGParallel(DcmItem& dataset, const Uint32 numThreads);
+
+    /** Write Per-Frame Functional Group Sequence to given item in sequential mode,
+     * i.e.\ no extra threads are used.
+     *  @param  dataset The item to write to
+     *  @return EC_Normal if writing was successful, error otherwise
+     */
+    virtual OFCondition writePerFrameFGSequential(DcmItem& dataset);
+
     /** Convert a shared functional group to a per-frame one by copying the
      *  shared one into a per-frame one for each frame and deleting the shared one
-     *  aftewrards.
+     *  afterwards.
      *  @param  fgType The type of functional group to convert
      *  @return EC_Normal if conversion worked out, FG_EC_NoSuchGroup if such a
      *          group does not exist and other error otherwise. In the last case
@@ -284,6 +317,150 @@ protected:
      */
     virtual OFCondition convertSharedToPerFrame(const DcmFGTypes::E_FGType fgType);
 
+    /** Find an adequate number of threads to use for reading and writing per-frame functional groups.
+     *  The number is adjusted to the number of frames, i.e.\ there will be no more threads used
+     *  than one fifth the number of frames (so that each thread must at least handle
+     *  5 frames, since otherwise the overhead of starting threads would be too high).
+     *  @param numFrames The number of frames to read/write
+     *  @param userThreadSetting The user-defined number of threads to use
+     *  @return The adjusted number of threads to use
+     */
+    virtual Uint32 findAdequateNumberOfThreads(const Uint32 numFrames, const Uint32 userThreadSetting);
+
+    /// Threaded functional group writer, used to write per-frame functional groups
+    /// in parallel. Each thread gets assigned some frames and writes the functional groups
+    /// for those frames to the output vector.
+    struct ThreadedFGWriter : public OFThread
+    {
+        /// Vector of pairs of frame number and functional groups to write for that frame
+        OFVector<OFPair<Uint32, FunctionalGroups*> >* m_frameGroups;
+        /// Output vector, where the per-frame items are written to
+        /// (one item per frame containing all functional groups for that frame).
+        //  All threads write to the same vector, so it must be protected by a mutex.
+        /// The vector is resized to the total number of frames before starting the threads.
+        OFVector<DcmItem*>* m_perFrameResultItems;
+        /// Mutex to protect the output vector
+        OFMutex* m_perFrameResultItemsMutex;
+        /// Start frame this thread should handle (inclusive, starts with 0)
+        Uint32 m_startFrame;
+        /// End frame this thread should handle (exclusive, i.e.\ the last frame
+        /// this thread handles is m_endFrame - 1)
+        Uint32 m_endFrame;
+        /// Mutex to protect error output
+        OFMutex* m_errorMutex;
+        /// Pointer to a condition variable that is set if an error occurs
+        /// during writing. This is used to signal the main thread that an error
+        /// occurred during writing. The main thread can then check the error
+        /// condition variable to see if an error occurred and handle it accordingly.
+        OFConditionConst* m_errorOccurred;
+
+        /** Initialize the thread
+         * @param frameGroups Input vector of pairs of frame number and functional groups to write for that frame
+         * @param perFrameResultItems Output vector, where the per-frame items are written to,
+         *   (frame number as index, one item per frame containing all functional groups for that frame).
+         * @param perFrameResultItemsMutex Mutex to protect the output vector
+         * @param startFrame Start frame this thread should handle (inclusive, starts with 0)
+         * @param endFrame End frame this thread should handle (exclusive, i.e.\ the last frame this thread handles is m_endFrame - 1)
+         * @param errorOccurred Pointer to a condition variable that is set if an error occurs
+         * @param errorMutex Mutex to protect error output
+         */
+        void init(OFVector<OFPair<Uint32, FunctionalGroups*> >* frameGroups,
+                  OFVector<DcmItem*>* perFrameResultItems,
+                  OFMutex* perFrameResultItemsMutex,
+                  const Uint32 startFrame,
+                  const Uint32 endFrame,
+                  OFConditionConst* errorOccurred,
+                  OFMutex* errorMutex);
+
+        /// Default constructor
+        ThreadedFGWriter();
+
+        /// Destructor, nothing to do
+        ~ThreadedFGWriter();
+
+        /** Run method, called by OFThread::start()
+         *  This method will write the functional groups for the frames assigned
+         *  to this thread to the output vector. It will stop in case of an error
+         *  and set the error condition variable to indicate that an error occurred.
+         */
+        void run();
+    };
+
+    /// Threaded functional group reader, used to read per-frame functional groups
+    /// in parallel. Each thread gets assigned some frames and reads the functional groups
+    /// for those frames from the input vector.
+    /// The results are stored in the output vector, which is protected by a mutex.
+    struct ThreadedFGReader : public OFThread
+    {
+        /// Input vector of per-frame items, one item per frame
+        /// containing all functional groups for that frame.
+        OFVector<DcmItem*>* m_perFrameItems;
+        /// Mutex to protect the input vector
+        OFMutex* m_perFrameItemsMutex;
+        /// Output vector of per-frame functional groups, one item per frame
+        /// containing all functional groups for that frame.
+        PerFrameGroups* m_frameResultGroups;
+        /// Mutex to protect the output vector
+        OFMutex* m_frameResultGroupsMutex;
+        /// Start frame this thread should handle (inclusive, starts with 0)
+        /// (i.e.\ the first frame this thread handles is m_startFrame)
+        Uint32 m_startFrame;
+        /// End frame this thread should handle (exclusive, i.e.\ the last frame
+        /// this thread handles is m_endFrame - 1)
+        Uint32 m_endFrame;
+        /// Mutex to protect error output
+        OFMutex* m_errorMutex;
+        /// Pointer to a condition variable that is set if an error occurs
+        /// during reading. This is used to signal the main thread that an error
+        /// occurred during reading. The main thread can then check the error
+        /// condition variable to see if an error occurred and handle it accordingly.
+        OFConditionConst* m_errorOccurred;
+        /// Pointer to the FGInterface instance to read from. This is used to
+        /// access the FGInterface methods for reading functional groups.
+        /// It is set by the init() method and used in the run() method to read
+        /// each functional group
+        FGInterface* m_fgInterfacePtr; // Pointer to the FGInterface instance to read from
+
+        /** Initialize the thread
+         * @param perFrameItems Input vector of per-frame items, one item per frame
+         *        containing all functional groups for that frame.
+         * @param perFrameItemsMutex Mutex to protect the input vector
+         * @param m_frameResultGroups Output vector of per-frame functional groups,
+         *        one item per frame (index = frame number) containing all functional groups for that frame.
+         * @param frameResultGroupsMutex Mutex to protect the output vector
+         * @param startFrame Start frame this thread should handle (inclusive, starts with 0)
+         * @param endFrame End frame this thread should handle (exclusive, i.e.\ the last frame this thread handles is m_endFrame - 1)
+         * @param errorMutex Mutex to protect error output
+         * @param errorOccurred Pointer to a condition variable that is set if an error occurs
+         *        during reading. The main thread can check this variable to see if an error occurred.
+         * @param fgInterfacePtr Pointer to the FGInterface instance;
+         *        used to access its readSingleFG() method
+         */
+        void init(OFVector<DcmItem*>* perFrameItems,
+                  OFMutex* perFrameItemsMutex,
+                  PerFrameGroups* m_frameResultGroups,
+                  OFMutex* frameResultGroupsMutex,
+                  Uint32 startFrame,
+                  Uint32 endFrame,
+                  OFMutex* errorMutex,
+                  OFConditionConst* errorOccurred,
+                  FGInterface* fgInterfacePtr);
+
+        /// Default constructor
+        ThreadedFGReader();
+
+        /// Destructor
+        ~ThreadedFGReader();
+
+        /** Run method, called by OFThread::start()
+         *  This method will read the functional groups for the frames assigned
+         *  to this thread from the input vector and store them in the output vector.
+         *  It will stop in case of an error and set the error condition variable
+         *  to indicate that an error occurred.
+         */
+        void run();
+    };
+
 private:
     /// Shared functional groups
     FunctionalGroups m_shared;
@@ -295,6 +472,14 @@ private:
     /// If enabled, functional group structure is checked on write(). Otherwise,
     /// checks are skipped.
     OFBool m_checkOnWrite;
+
+    /// Maximum number of threads to use for reading and writing per-frame functional groups,
+    /// default is 1 thread (sequential writing). The number provided by the user
+    /// will be adjusted to the number of frames, i.e. there will be not more threads
+    /// used than one fifth the number of frames (so that each thread must at least handle
+    //  10 frames, since otherwise the overhead of starting threads would be too high). The
+    /// number is adjusted on the fly.
+    Uint32 m_numThreads;
 };
 
 #endif // MODMULTIFRAMEFGH_H
index 19136d9a30f8e2d6ab15e8dff00be72ec3712cd3..3b7cc1b017a138061afd0b26b7065cbb6bfe6090 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -97,7 +97,7 @@ public:
      */
     virtual OFCondition getReferencedSegmentNumber(Uint16& value, const unsigned long pos = 0);
 
-    /** Set Referenced Segment Number
+    /** Set Referenced Segment Number (starting from 1)
      *  @param  segmentNumber Value to be set
      *  @return EC_Normal if successful, an error code otherwise
      */
index 52e849ff1a385b0c7a39efcea00f4511bf9f030b..cfdb167f91ae90e1d78cf8a36de25684e39fdfd9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -102,6 +102,8 @@ extern DCMTK_DCMFG_EXPORT const OFConditionConst FG_EC_InconsistentConcatenation
 extern DCMTK_DCMFG_EXPORT const OFConditionConst FG_EC_ConcatenationComplete;
 /// Unsupported pixel data layout
 extern DCMTK_DCMFG_EXPORT const OFConditionConst FG_EC_UnsupportedPixelDataLayout;
+/// Parallel processing failed
+extern DCMTK_DCMFG_EXPORT const OFConditionConst FG_EC_ParallelProcessingFailed;
 
 /*---------------------*
  *  class declaration  *
@@ -114,6 +116,13 @@ class DCMTK_DCMFG_EXPORT DcmFGTypes
 {
 
 public:
+
+    // --- Constants ---
+
+    /// Maximum number of frames, limited by
+    /// Number of Frames attribute which maxes out at 2^31-1.
+    static const Uint32 DCMFG_MAX_FRAMES = 2147483647;
+
     // --- Type definitions ---
 
     /** Functional group types
diff --git a/dcmfg/include/dcmtk/dcmfg/framesorter.h b/dcmfg/include/dcmtk/dcmfg/framesorter.h
new file mode 100644 (file)
index 0000000..e918c9d
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ *  Copyright (C) 2015-2025, Open Connections GmbH
+ *
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmfg
+ *
+ *  Author:  Andrey Fedorov
+ *
+ *  Purpose: Abstract base class for sorting frames of a functional group
+ *
+ */
+
+#ifndef FRAMESORTER_H
+#define FRAMESORTER_H
+
+#include "dcmtk/config/osconfig.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/ofstd/ofvector.h"
+#include "dcmtk/ofstd/ofstring.h"
+#include "dcmtk/ofstd/ofmath.h"
+#include "dcmtk/dcmfg/fginterface.h"
+#include "dcmtk/dcmfg/fgplanpo.h"
+#include "dcmtk/dcmfg/fgplanor.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmfg/fgtypes.h"
+
+#include <stdlib.h>                     // for qsort
+
+typedef OFVector<Float64> ImagePosition;      // Image Position Patient
+typedef OFPair<Uint32, Float64> FrameWithPos; // DICOM frame number and Image Position Patient
+
+/** Abstract class for sorting a set of frames in a functional group. The
+ *  sorting criteria are up to the actual implementation classes.
+ */
+class FrameSorter
+{
+
+public:
+
+  /** Structure that transports the results of a frame sorting operation
+   */
+  struct Results
+  {
+    /** Default constructor, initializes empty results
+     */
+    Results() :
+      errorCode(EC_Normal),
+      frameNumbers(),
+      key(DCM_UndefinedTagKey),
+      fgSequenceKey(DCM_UndefinedTagKey),
+      fgPrivateCreator() { }
+
+    /** Clear all results, i.e. reset to default state
+     */
+    void clear()
+    {
+      errorCode = EC_Normal;
+      frameNumbers.clear();
+      key = DCM_UndefinedTagKey;
+      fgSequenceKey = DCM_UndefinedTagKey;
+      fgPrivateCreator = "";
+    }
+
+    /// Error code: EC_Normal if sorting was successful, error code otherwise.
+    /// The error code should be set in any case (default: EC_Normal)
+    OFCondition errorCode;
+    /// The frame numbers, in sorted order (default: empty)
+    OFVector<Uint32> frameNumbers;
+    /// The frame positions, in sorted order, if provided
+    /// by the sorter (default: empty). If not empty, contains the same number
+    /// of items as frameNumbers.
+    OFVector<ImagePosition> framePositions;
+    /// Tag key that contains the information that was crucial for sorting.
+    /// This is especially useful for creating dimension indices. Should be
+    /// set to (0xffff,0xfff) if none was used (default).
+    DcmTagKey key;
+    /// Tag functional group sequence key that contains the tag key (see other member)
+    /// that was crucial for sorting.
+    /// This is especially useful for creating dimension indices. Should be
+    /// set to (0xffff,0xfff) if none was used (default).
+    DcmTagKey fgSequenceKey;
+    /// Tag functional group sequence's private creator string for the fgSequenceKey
+    /// result member if fgSequenceKey is a private attributes.
+    /// This is especially useful for creating dimension indices that base on private
+    /// attibutes. Should be left empty if fgSequenceKey is not private or fgSequenceKey
+    /// is not used at all (default).
+    OFString fgPrivateCreator;
+  };
+
+  /** Structure that holds Image Position (Patient) values for frames
+   */
+  struct FramePositions
+  {
+    OFVector<ImagePosition> positions;
+  };
+
+  /** Default constructor, does nothing
+   */
+  FrameSorter()
+  : m_fg(NULL)
+  {}
+
+  /** Set input data for this sorter
+   *  @param  fg The functional groups to work on. Ownership
+   *          of pointer stays with the caller.
+   */
+  void setSorterInput(FGInterface* fg)
+  {
+    m_fg = fg;
+  }
+
+  /** Virtual default desctructor, does nothing
+   */
+  virtual ~FrameSorter() {}
+
+  /** Return a frame order that is determined by the implementation of the particular
+   *  derived class. E.g. a sorting by Plane Position (Patient) could be implemented.
+   *  @param  results The results of the sorting procedure. Should be empty (cleared)
+   *          when handed into the function.
+   */
+  virtual void sort(Results& results) =0;
+
+  /** Get description of the sorting algorithm this class uses.
+   *  @return Free text description of the sorting algorithm used.
+   */
+  virtual OFString getDescription() =0;
+
+
+  // Derived classes may add further functions, e.g. to provide further parameters,
+  // like the main dataset, frame data, etc.
+
+
+protected:
+
+  /// Pointer to functional groups to work on. Not owned by this class.
+  FGInterface* m_fg;
+};
+
+/** Dummy sorter implementing the FrameSorter interface,
+ *  but not doing any sorting at all. As a result it provides
+ *  a list of frames in their natural order, as found in the underlying
+ *  DICOM dataset. The results will not contain frame position
+ *  to make this implementation as lightweight and "stupid" as possible.
+ */
+class FrameSorterIdentity : public FrameSorter
+{
+
+public:
+
+  /**
+  *  Default constructor, does nothing
+  */
+  FrameSorterIdentity(){};
+
+  /**
+   *  Virtual default destructor, does nothing
+   */
+  virtual ~FrameSorterIdentity()
+  {
+
+  }
+
+  /** Get description of the sorting algorithm this class uses.
+   *  @return Free text description of the sorting algorithm used.
+   */
+  virtual OFString getDescription()
+  {
+    return "Returns frames in the order defined in the functional group, i.e. as defined in the image file";
+  }
+
+  /** Performs actual sorting. Does only set Results.frameNumbers and errorCode,
+   *  leaving the rest untouched.
+   *  @param  results The results produced by dummy sorter (list of frame numbers as
+   *          found in the underlying DICOM dataset, and EC_Normal as error code)
+   */
+  virtual void sort(Results& results)
+  {
+    if (m_fg == NULL)
+    {
+      results.errorCode = FG_EC_InvalidData;
+      return;
+    }
+
+    size_t numFrames = m_fg->getNumberOfFrames();
+    if (numFrames == 0)
+    {
+      results.errorCode = FG_EC_NotEnoughItems;
+      return;
+    }
+
+    for (Uint32 count = 0; count < numFrames; count++)
+    {
+      results.frameNumbers.push_back(count);
+    }
+    return;
+  }
+
+};
+
+/** Sorter implementing the FrameSorter interface that sorts frames
+ *  by their Image Position (Patient) attribute. The sorting is done
+ *  by projecting the Image Position (Patient) on the slice direction
+ *  (as defined by the Image Orientation (Patient) attribute).
+ */
+class FrameSorterIPP : public FrameSorter
+{
+public:
+
+  /** Structure that holds a frame for sorting
+   */
+  struct OrderedFrameItem
+  {
+    OrderedFrameItem() :
+      key(),
+      frameId()
+    {}
+
+    /// The key relevant for sorting
+    Float64 key;
+    /// The DICOM frame number
+    Uint32 frameId;
+    /// The frame position as found in Image Position (Patient)
+    ImagePosition framePos;
+  };
+
+
+  /** Default constructor, does nothing
+   */
+  ~FrameSorterIPP(){};
+
+  /** Get description of the sorting algorithm this class uses.
+   *  @return Free text description of the sorting algorithm used.
+   */
+  OFString getDescription(){
+    return "Returns frames in the order defined by projecting the ImagePositionPatient on the slice direction.";
+  }
+
+  /** Get the slice direction from Image Orientation (Patient)
+   *  @param  results The results structure to hold error code in case of failure
+   */
+  void getSliceDirection(Results &results)
+  {
+    OFBool isPerFrame;
+    FGPlaneOrientationPatient *planorfg = OFstatic_cast(FGPlaneOrientationPatient*,
+                                                        m_fg->get(0, DcmFGTypes::EFG_PLANEORIENTPATIENT, isPerFrame));
+    if(!planorfg || isPerFrame){
+      results.errorCode = FG_EC_InvalidData;
+      return;
+    }
+
+    OFVector<Float64> dirX, dirY;
+    OFString orientStr;
+    for(int i=0;i<3;i++){
+      if(planorfg->getImageOrientationPatient(orientStr, i).good()){
+        dirX.push_back(atof(orientStr.c_str()));
+      } else {
+        results.errorCode = FG_EC_InvalidData;
+        break;
+      }
+    }
+    for(int i=3;i<6;i++){
+      if(planorfg->getImageOrientationPatient(orientStr, i).good()){
+        dirY.push_back(atof(orientStr.c_str()));
+      } else {
+        results.errorCode = FG_EC_InvalidData;
+        break;
+      }
+    }
+
+    if(results.errorCode != EC_Normal)
+      return;
+
+    sliceDirection = cross_3d(dirX, dirY);
+    normalize(sliceDirection);
+  }
+
+  /** Performs actual sorting. Sets given results.
+   *  @param  results The results produced by IPP sorter (list of frame numbers sorted
+   *          by Image Position (Patient) projection on slice direction, and EC_Normal
+   *          as error code in case of success)
+   */
+  void sort(Results& results)
+  {
+    if(m_fg == NULL){
+      results.errorCode = FG_EC_InvalidData;
+      return;
+    }
+
+    getSliceDirection(results);
+    if(results.errorCode != EC_Normal){
+      return;
+    }
+
+    OFBool isPerFrame;
+    size_t numFrames = m_fg->getNumberOfFrames();
+    if (numFrames > DcmFGTypes::DCMFG_MAX_FRAMES)
+    {
+        results.errorCode = FG_EC_TooManyItems;
+        return;
+    }
+    OrderedFrameItem* orderedFrameItems = new OrderedFrameItem[numFrames];
+
+    for(Uint32 frameId=0;frameId<numFrames;frameId++)
+    {
+      FGPlanePosPatient *planposfg =
+        OFstatic_cast(FGPlanePosPatient*,m_fg->get(frameId, DcmFGTypes::EFG_PLANEPOSPATIENT, isPerFrame));
+
+      if(!planposfg || !isPerFrame){
+        results.errorCode = FG_EC_InvalidData;
+        return;
+      }
+
+      ImagePosition sOrigin;
+      for(int j=0;j<3;j++){
+        OFString planposStr;
+        if(planposfg->getImagePositionPatient(planposStr, j).good()){
+          sOrigin.push_back(atof(planposStr.c_str()));
+        } else {
+          results.errorCode = FG_EC_InvalidData;
+          return;
+        }
+      }
+
+      Float64 dist;
+      dist = dot(sliceDirection, sOrigin);
+      orderedFrameItems[frameId].key = dist;
+      orderedFrameItems[frameId].frameId = frameId;
+      orderedFrameItems[frameId].framePos = sOrigin;
+    }
+
+    qsort(&orderedFrameItems[0], numFrames, sizeof(OrderedFrameItem), &compareIPPKeys);
+
+    for(Uint32 count=0;count<numFrames;count++)
+    {
+      results.frameNumbers.push_back(orderedFrameItems[count].frameId);
+      results.framePositions.push_back(orderedFrameItems[count].framePos);
+    }
+
+    delete [] orderedFrameItems;
+
+    return;
+  }
+
+private:
+
+  /** Calculate the cross product of two 3D vectors.
+   *  @param v1 First vector
+   *  @param v2 Second vector
+   *  @return Cross product vector
+   */
+  OFVector<Float64> cross_3d(OFVector<Float64> v1, OFVector<Float64> v2){
+    OFVector<Float64> result;
+    result.push_back(v1[1]*v2[2]-v1[2]*v2[1]);
+    result.push_back(v1[2]*v2[0]-v1[0]*v2[2]);
+    result.push_back(v1[0]*v2[1]-v1[1]*v2[0]);
+
+    return result;
+  }
+
+  /** Calculate the dot product of two 3D vectors.
+   *  @param v1 First vector
+   *  @param v2 Second vector
+   *  @return Dot product value
+   */
+  Float64 dot(OFVector<Float64> v1, OFVector<Float64> v2){
+    return Float64(v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
+  }
+
+  /** Normalize a 3D vector.
+   *  @param v The vector to normalize (output parameter)
+   */
+  void normalize(OFVector<Float64> &v){
+    double norm = OFMath::sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
+    v[0] = v[0]/norm;
+    v[1] = v[1]/norm;
+    v[2] = v[2]/norm;
+  }
+
+
+  /** Compare function for qsort to sort OrderedFrameItem by their key.
+   *  @param a Pointer to first OrderedFrameItem
+   *  @param b Pointer to second OrderedFrameItem
+   *  @return Negative value if a < b, zero if a == b, positive if a > b
+   */
+  static int compareIPPKeys(const void *a, const void *b);
+
+  /// The slice direction vector
+  OFVector<Float64> sliceDirection;
+
+};
+
+/** Compare function to compare OrderedFrameItem by their key.
+ *  @param a Pointer to first OrderedFrameItem
+ *  @param b Pointer to second OrderedFrameItem
+ *  @return Returns 1 for a > b, -1 otherwise
+ */
+int FrameSorterIPP::compareIPPKeys(const void *a, const void *b)
+{
+  FrameSorterIPP::OrderedFrameItem *i1, *i2;
+  i1 = (FrameSorterIPP::OrderedFrameItem*) a;
+  i2 = (FrameSorterIPP::OrderedFrameItem*) b;
+  if(i1->key > i2->key)
+    return 1;
+  else
+    return -1;
+}
+
+#endif // FRAMESORTHER_H
index 8ed93f8f35053ea18b466cc0aeb411c0c7db18dd..7b3bc5188666a84be4afbaafcc28a6f485ce1f6c 100644 (file)
@@ -70,7 +70,11 @@ concatenationcreator.o: concatenationcreator.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmfg/concatenationcreator.h \
- ../include/dcmtk/dcmfg/fgdefine.h ../include/dcmtk/dcmfg/fgtypes.h
+ ../include/dcmtk/dcmfg/fgdefine.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../include/dcmtk/dcmfg/fgtypes.h
 concatenationloader.o: concatenationloader.cc \
  ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -141,6 +145,7 @@ concatenationloader.o: concatenationloader.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -347,6 +352,7 @@ fgctacquisitiondetails.o: fgctacquisitiondetails.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -424,6 +430,7 @@ fgctacquisitiontype.o: fgctacquisitiontype.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -505,6 +512,7 @@ fgctadditionalxraysource.o: fgctadditionalxraysource.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -584,6 +592,7 @@ fgctexposure.o: fgctexposure.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
@@ -667,6 +676,7 @@ fgctgeometry.o: fgctgeometry.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -743,6 +753,7 @@ fgctimageframetype.o: fgctimageframetype.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -817,6 +828,7 @@ fgctposition.o: fgctposition.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -897,6 +909,7 @@ fgctreconstruction.o: fgctreconstruction.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -972,6 +985,7 @@ fgcttabledynamics.o: fgcttabledynamics.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1052,6 +1066,7 @@ fgctxraydetails.o: fgctxraydetails.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1118,21 +1133,23 @@ fgderimg.o: fgderimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
- ../include/dcmtk/dcmfg/fgderimg.h ../include/dcmtk/dcmfg/fgbase.h \
- ../include/dcmtk/dcmfg/fgtypes.h ../include/dcmtk/dcmfg/fgdefine.h \
+ ../include/dcmtk/dcmfg/fgderimg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../include/dcmtk/dcmfg/fgbase.h ../include/dcmtk/dcmfg/fgtypes.h \
+ ../include/dcmtk/dcmfg/fgdefine.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
@@ -1222,6 +1239,7 @@ fgfact.o: fgfact.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../include/dcmtk/dcmfg/fgctgeometry.h \
@@ -1231,7 +1249,6 @@ fgfact.o: fgfact.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmfg/fgcttabledynamics.h \
  ../include/dcmtk/dcmfg/fgctxraydetails.h \
  ../include/dcmtk/dcmfg/fgderimg.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
  ../include/dcmtk/dcmfg/fgfact.h ../include/dcmtk/dcmfg/fgfracon.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
@@ -1256,6 +1273,7 @@ fgfact.o: fgfact.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmfg/fgtemporalposition.h \
  ../include/dcmtk/dcmfg/fgusimagedescription.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h
 fgfracon.o: fgfracon.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -1339,6 +1357,7 @@ fgfracon.o: fgfracon.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h
 fgframeanatomy.o: fgframeanatomy.cc \
  ../../config/include/dcmtk/config/osconfig.h \
@@ -1417,6 +1436,7 @@ fgframeanatomy.o: fgframeanatomy.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
@@ -1500,6 +1520,7 @@ fgframevoilut.o: fgframevoilut.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1578,6 +1599,7 @@ fgimagedatatype.o: fgimagedatatype.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1721,6 +1743,7 @@ fgirradiationeventid.o: fgirradiationeventid.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1797,6 +1820,7 @@ fgparametricmapframetype.o: fgparametricmapframetype.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1876,6 +1900,7 @@ fgpixeltransform.o: fgpixeltransform.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -1951,6 +1976,7 @@ fgpixmsr.o: fgpixmsr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2027,6 +2053,7 @@ fgplanor.o: fgplanor.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2102,6 +2129,7 @@ fgplanorvol.o: fgplanorvol.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2178,6 +2206,7 @@ fgplanpo.o: fgplanpo.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2253,6 +2282,7 @@ fgplanposvol.o: fgplanposvol.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2334,6 +2364,7 @@ fgrealworldvaluemapping.o: fgrealworldvaluemapping.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrss.h \
@@ -2414,6 +2445,7 @@ fgseg.o: fgseg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2489,6 +2521,7 @@ fgtemporalposition.o: fgtemporalposition.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -2605,6 +2638,7 @@ fgusimagedescription.o: fgusimagedescription.cc \
  ../include/dcmtk/dcmfg/fgdefine.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
@@ -2712,4 +2746,5 @@ stackinterface.o: stackinterface.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
- ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def
index 7143b0bcb4a1471ebaa166e675abb98c18be197a..764a3e69899753e1d039da08a276456b53af90fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -30,7 +30,6 @@
 #include "dcmtk/dcmfg/concatenationcreator.h"
 #include "dcmtk/dcmfg/fgtypes.h"
 
-
 // Maximum number of instances that make up a Concatenation
 const Uint16 ConcatenationCreator::m_MAX_INSTANCES_PER_CONCATENATION = 65535;
 
@@ -69,37 +68,48 @@ ConcatenationCreator::~ConcatenationCreator()
     if (m_cfgTransferOwnership)
     {
         delete m_srcDataset;
-        delete[] m_srcPixelData;
     }
+    // knows whether to free pixel data or not
+    delete m_srcPixelData;
 }
 
 OFCondition ConcatenationCreator::setCfgInput(DcmItem* srcDataset, OFBool transferOwnership)
 {
     // Check pixel data exists and is in native format (i.e. uncompressed)
-    DcmElement* elem = NULL;
-    srcDataset->findAndGetElement(DCM_PixelData, elem);
-    if (!elem)
-        return FG_EC_PixelDataMissing;
-    DcmPixelData* pixDataElem = OFstatic_cast(DcmPixelData*, elem);
-    if (!pixDataElem)
-        return FG_EC_PixelDataMissing;
-    if (!pixDataElem->canWriteXfer(EXS_LittleEndianExplicit, EXS_LittleEndianExplicit /* ignored */))
-        return EC_UnsupportedEncoding;
-    OFCondition result = pixDataElem->getUint8Array(m_srcPixelData);
-    if (!m_srcPixelData || result.bad())
-        return FG_EC_PixelDataMissing;
+    OFCondition result = initSrcPixelData(srcDataset, transferOwnership);
+    if (result.good())
+    {
+        m_srcDataset = srcDataset;
+        m_cfgTransferOwnership = transferOwnership;
+    }
 
-    m_srcDataset = srcDataset;
+    return result;
+}
 
+OFCondition ConcatenationCreator::setCfgInput(DcmItem* srcDataset,
+                                              Uint8* pixelData,
+                                              size_t pixelDataLength,
+                                              OFBool transferOwnership)
+{
+    // Check input parameters
+    if (!pixelData)
+        return FG_EC_PixelDataMissing;
+
+    m_srcDataset           = srcDataset;
+    delete m_srcPixelData;
+    m_srcPixelData  = NULL;
+    m_srcPixelData         = new DcmIODTypes::Frame<Uint8>(pixelData, pixelDataLength);
+    m_srcPixelData->setReleaseMemory(transferOwnership);
     m_cfgTransferOwnership = transferOwnership;
 
     // All fine
     return EC_Normal;
 }
 
+
 OFCondition ConcatenationCreator::setCfgInput(DcmItem* srcDataset,
-                                              Uint8* pixelData,
-                                              size_t /* pixelDataLength */,
+                                              Uint16* pixelData,
+                                              size_t pixelDataLength,
                                               OFBool transferOwnership)
 {
     // Check input parameters
@@ -107,13 +117,17 @@ OFCondition ConcatenationCreator::setCfgInput(DcmItem* srcDataset,
         return FG_EC_PixelDataMissing;
 
     m_srcDataset           = srcDataset;
-    m_srcPixelData         = pixelData;
+    delete m_srcPixelData;
+    m_srcPixelData  = NULL;
+    m_srcPixelData         = new DcmIODTypes::Frame<Uint16>(pixelData, pixelDataLength);
+    m_srcPixelData->setReleaseMemory(transferOwnership);
     m_cfgTransferOwnership = transferOwnership;
 
     // All fine
     return EC_Normal;
 }
 
+
 OFCondition ConcatenationCreator::setCfgFramesPerInstance(Uint32 numFramesPerInstance)
 {
     m_cfgNumFramesPerInstance = numFramesPerInstance;
@@ -173,9 +187,10 @@ OFCondition ConcatenationCreator::writeNextInstance(DcmItem& dstDataset)
     {
         return EC_MemoryExhausted;
     }
+    // Setting VR is necessary if Pixel Data is actually 16 bit
     dstPixelData->setVR(m_VRPixelData);
     size_t srcPos = (m_numBitsFrame * m_currentSrcFrame) / 8;
-    memcpy(dstData, &m_srcPixelData[srcPos], numTotalBytesInstance);
+    memcpy(dstData, &(OFstatic_cast(Uint8*, m_srcPixelData->getPixelData())[srcPos]), numTotalBytesInstance);
     result = dstDataset.insert(dstPixelData.release());
     if (result.good())
     {
@@ -489,3 +504,45 @@ OFCondition ConcatenationCreator::configureCommon()
     m_configured = OFTrue;
     return result;
 }
+
+
+OFCondition ConcatenationCreator::initSrcPixelData(DcmItem* srcDataset, OFBool transferOwnership)
+{
+    // Check pixel data exists and is in native format (i.e. uncompressed)
+    DcmElement* elem = NULL;
+    srcDataset->findAndGetElement(DCM_PixelData, elem);
+    if (!elem)
+        return FG_EC_PixelDataMissing;
+    DcmPixelData* pixDataElem = OFstatic_cast(DcmPixelData*, elem);
+    if (!pixDataElem)
+        return FG_EC_PixelDataMissing;
+    if (!pixDataElem->canWriteXfer(EXS_LittleEndianExplicit, EXS_LittleEndianExplicit /* ignored */))
+        return EC_UnsupportedEncoding;
+    size_t pixDataLength = pixDataElem->getLength();
+    Uint16 bitsAllocated = 0;
+    srcDataset->findAndGetUint16(DCM_BitsAllocated, bitsAllocated);
+       if ((bitsAllocated != 8) && (bitsAllocated != 16) && (bitsAllocated != 1))
+        return FG_EC_UnsupportedPixelDataLayout;
+
+    OFCondition result;
+    if (bitsAllocated <= 8)
+    {
+        Uint8 *pixelData = NULL;
+        result = pixDataElem->getUint8Array(pixelData);
+        if (!pixelData || result.bad())
+            return FG_EC_PixelDataMissing;
+        m_srcPixelData = new DcmIODTypes::Frame<Uint8>(pixelData, pixDataLength);
+    }
+    else // bits allocated = 16
+    {
+        Uint16 *pixelData = NULL;
+        result = pixDataElem->getUint16Array(pixelData);
+        if (!pixelData || result.bad())
+            return FG_EC_PixelDataMissing;
+        m_srcPixelData = new DcmIODTypes::Frame<Uint16>(pixelData, pixDataLength);
+    }
+    m_srcPixelData->setReleaseMemory(transferOwnership);
+    return EC_Normal;
+
+
+}
index d7a81f56f26311f8d5fbc9d4d9b83fbd174fb02a..8c7b6e0f1863fe59aa81483cbc4ffacb12d40e66 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, Open Connections GmbH
+ *  Copyright (C) 2019-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -223,7 +223,7 @@ const ConcatenationLoader::TScanFailures& ConcatenationLoader::getFailedFiles()
 }
 
 OFCondition
-ConcatenationLoader::load(const OFString& concatenationUID, DcmDataset* dataset, OFVector<DcmIODTypes::Frame*>& frames)
+ConcatenationLoader::load(const OFString& concatenationUID, DcmDataset* dataset, OFVector<DcmIODTypes::FrameBase*>& frames)
 {
     if (dataset == NULL)
         return EC_IllegalParameter;
@@ -333,33 +333,55 @@ OFCondition ConcatenationLoader::deleteConcatAttributes(DcmItem& item)
 
 OFCondition ConcatenationLoader::extractFrames(DcmItem& item, Info& info, const Uint32 numFrames)
 {
-    const Uint8* pixData = NULL;
-    OFCondition result   = item.findAndGetUint8Array(DCM_PixelData, pixData);
-    if (result.good() && pixData)
+    const Uint8* pixData8 = NULL;
+    const Uint16* pixData16 = NULL;
+    OFCondition result;
+    if (info.m_BitsAlloc <= 8)
+    {
+        result = item.findAndGetUint8Array(DCM_PixelData, pixData8);
+    }
+    else if (info.m_BitsAlloc == 16)
+    {
+        result = item.findAndGetUint16Array(DCM_PixelData, pixData16);
+    }
+    else
+    {
+        DCMFG_ERROR("Bits Allocated=" << info.m_BitsAlloc << " not supported, must be 1, 8 or 16");
+        return FG_EC_UnsupportedPixelDataLayout;
+    }
+    if (result.good() && (pixData8 || pixData16))
     {
         size_t bytesPerFrame = 0;
         result                 = computeBytesPerFrame(info.m_Rows, info.m_Cols, info.m_BitsAlloc, bytesPerFrame);
         if (result.good())
         {
-            const Uint8* ptr = pixData;
             for (Uint32 f = 0; f < numFrames; f++)
             {
-                DcmIODTypes::Frame* frame = new DcmIODTypes::Frame();
-                if (frame)
+                DcmIODTypes::FrameBase* frame = NULL;
+                if (info.m_BitsAlloc <= 8) // 8 or 1
                 {
-                    frame->length  = bytesPerFrame;
-                    frame->pixData = new Uint8[frame->length];
-                    if (frame->pixData)
+                    frame = new DcmIODTypes::Frame<Uint8>(bytesPerFrame);
+                    if (frame && frame->getPixelData())
                     {
-                        memcpy(frame->pixData, ptr, frame->length);
-                        ptr += frame->length;
-                        m_Frames.push_back(frame);
+                        const Uint8* ptr = pixData8 + f * frame->getLengthInBytes();
+                        memcpy(frame->getPixelData(), ptr, frame->getLengthInBytes());
                     }
-                    else
+                }
+                else if (info.m_BitsAlloc == 16)
+                {
+                    frame = new DcmIODTypes::Frame<Uint16>(bytesPerFrame / 2);
+                    if (frame && frame->getPixelData())
                     {
-                        result = EC_MemoryExhausted;
+                        // getLength() returns size in bytes, so divide by 2 since we advance by word
+                        const Uint16* ptr = pixData16 + f * frame->getLengthInBytes() / 2;
+                        // memcpy expects number of bytes to copy
+                        memcpy(frame->getPixelData(), ptr, frame->getLengthInBytes());
                     }
                 }
+                if (frame)
+                {
+                    m_Frames.push_back(frame);
+                }
                 else
                 {
                     result = EC_MemoryExhausted;
@@ -401,7 +423,7 @@ OFCondition ConcatenationLoader::computeBytesPerFrame(const Uint16 rows,
     // This is only different if bits allocated equals 1, which can happen
     // for binary segmentations or black and white secondary capture objects
     // (second SC generation).
-    // Other values than Bits Allocated 16 or 8 are not supported.
+    // Other values than Bits Allocated 16, 8 or 1 are not supported.
     bytes_per_frame = bitsAlloc * cols * rows;
     if ((bitsAlloc == 16) || (bitsAlloc == 8))
     {
index 401a1f23decb3c8e7065f3a5a2cfe6f03ffe23f9..afa8d5a964796885f4f9351ceb18337d57a42e48 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2019, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -45,6 +45,11 @@ void FunctionalGroups::clear()
     }
 }
 
+size_t FunctionalGroups::size() const
+{
+    return m_groups.size();
+}
+
 FGBase* FunctionalGroups::find(const DcmFGTypes::E_FGType fgType)
 {
     FGBase* group                   = NULL;
index 84ddd0a198faee7aee1b56f27737e4dae8cabd4a..4eccd9cf3d6205cfd5c7b7a60bc18ebb39959294 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -242,6 +242,7 @@ OFCondition FGDerivationImage::write(DcmItem& item)
 SourceImageItem::SourceImageItem()
     : m_PurposeOfReferenceCode()
     , m_ImageSOPInstanceReference()
+    , m_SpatialLocationsPreserved(DCM_SpatialLocationsPreserved)
 {
 }
 
@@ -254,6 +255,7 @@ SourceImageItem& SourceImageItem::operator=(const SourceImageItem& rhs)
 {
     m_PurposeOfReferenceCode    = rhs.m_PurposeOfReferenceCode;
     m_ImageSOPInstanceReference = rhs.m_ImageSOPInstanceReference;
+    m_SpatialLocationsPreserved = rhs.m_SpatialLocationsPreserved;
     return *this;
 }
 
@@ -261,6 +263,7 @@ void SourceImageItem::clearData()
 {
     m_PurposeOfReferenceCode.clearData();
     m_ImageSOPInstanceReference.clear();
+    m_SpatialLocationsPreserved.clear();
 }
 
 OFCondition SourceImageItem::check() const
@@ -281,6 +284,10 @@ int SourceImageItem::compare(const SourceImageItem& rhs) const
     {
         result = this->m_ImageSOPInstanceReference.compare(rhs.m_ImageSOPInstanceReference);
     }
+    if (result != 0)
+    {
+        result = this->m_SpatialLocationsPreserved.compare(rhs.m_SpatialLocationsPreserved);
+    }
 
     return result;
 }
@@ -295,12 +302,29 @@ ImageSOPInstanceReferenceMacro& SourceImageItem::getImageSOPInstanceReference()
     return m_ImageSOPInstanceReference;
 }
 
+OFCondition SourceImageItem::getSpatialLocationsPreserved(OFString& value, const long signed int pos) const
+{
+    return DcmIODUtil::getStringValueFromElement(m_SpatialLocationsPreserved, value, pos);
+}
+
+OFCondition SourceImageItem::setSpatialLocationsPreserved(const OFString& value, const OFBool checkValue)
+{
+    OFCondition result = (checkValue) ? DcmCodeString::checkStringValue(value, "1") : EC_Normal;
+    if (result.good())
+        result = m_SpatialLocationsPreserved.putOFStringArray(value);
+    return result;
+}
+
+
 OFCondition SourceImageItem::read(DcmItem& itemOfSourceImageSequence, const OFBool clearOldData)
 {
     /* Re-initialize object */
     if (clearOldData)
         clearData();
 
+    /* Spatial Locations Preserved */
+    DcmIODUtil::getAndCheckElementFromDataset(itemOfSourceImageSequence, m_SpatialLocationsPreserved, "1", "3", "DerivationImageMacro");
+
     /* Read Purpose of Reference Code Sequence */
     DcmIODUtil::readSingleItem<CodeSequenceMacro>(itemOfSourceImageSequence,
                                                   DCM_PurposeOfReferenceCodeSequence,
@@ -332,6 +356,13 @@ OFCondition SourceImageItem::write(DcmItem& itemOfSourceImageSequence)
         m_ImageSOPInstanceReference.write(itemOfSourceImageSequence);
     }
 
+    /** Currently only writes Spatial Locations Preserved */
+    if (result.good())
+    {
+        result = DcmIODUtil::copyElementToDataset(
+            result, itemOfSourceImageSequence, m_SpatialLocationsPreserved, "1" /* vm */, "3" /*requirement type*/, "DerivationImageMacro");
+    }
+
     return result;
 }
 
index 046d911618fb894ca51808860ee438dcf0e9f565..72418c43d687a322f389dbe8b58af6eb9b279061 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 #include "dcmtk/dcmfg/fgfact.h" // for creating new functional groups
 #include "dcmtk/dcmfg/fginterface.h"
 #include "dcmtk/ofstd/ofmap.h"
+#include "dcmtk/ofstd/ofthread.h"
 #include "dcmtk/ofstd/ofmem.h"
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcsequen.h"
 
+
+// ---------------------------------- ThreadedFGWriter ----------------------------------
+// This class is used to write functional groups in parallel for a group of frames, each.
+FGInterface::ThreadedFGWriter::ThreadedFGWriter()
+    : OFThread()
+    , m_frameGroups(OFnullptr)
+    , m_perFrameResultItems(OFnullptr)
+    , m_startFrame(0)
+    , m_endFrame(0)
+    , m_errorMutex(OFnullptr)
+{
+}
+
+void FGInterface::ThreadedFGWriter::init(OFVector<OFPair<Uint32, FunctionalGroups*> >* frameGroups,
+                                        OFVector<DcmItem*>* perFrameResultItems,
+                                        OFMutex* perFrameResultItemsMutex,
+                                        const Uint32 startFrame,
+                                        const Uint32 endFrame,
+                                        OFConditionConst* errorOccurred,
+                                        OFMutex* errorMutex)
+{
+    // Store the parameters in member variables
+    m_frameGroups = frameGroups;
+    m_perFrameResultItems = perFrameResultItems;
+    m_perFrameResultItemsMutex = perFrameResultItemsMutex;
+    m_startFrame = startFrame;
+    m_endFrame = endFrame;
+    m_errorOccurred = errorOccurred;
+    m_errorMutex = errorMutex;
+}
+
+
+FGInterface::ThreadedFGWriter::~ThreadedFGWriter()
+{
+    // Nothing to do here
+}
+
+void FGInterface::ThreadedFGWriter::run()
+{
+    if (!m_frameGroups || !m_perFrameResultItems)
+    {
+        DCMFG_ERROR("ThreadedFGWriter: Not properly initialized, cannot run.");
+        m_errorMutex->lock();
+        *m_errorOccurred = FG_EC_ParallelProcessingFailed;
+        m_errorMutex->unlock();
+        return;
+    }
+
+    // Iterate over all frames and write the functional groups
+    for (Uint32 idx = m_startFrame; idx < m_endFrame; ++idx)
+    {
+        Uint32 frameNo = m_frameGroups->at(idx).first;
+        FunctionalGroups* fgPtr = m_frameGroups->at(idx).second;
+        OFunique_ptr<DcmItem> perFrameItem(new DcmItem());
+
+        FunctionalGroups::iterator groupIt = fgPtr->begin();
+        while ((groupIt != fgPtr->end()))
+        {
+            m_errorMutex->lock();
+            if (*m_errorOccurred != EC_Normal)
+            {
+                m_errorMutex->unlock();
+                DCMFG_ERROR("Error occurred, stopping further processing.");
+                return;
+            }
+            m_errorMutex->unlock();
+            DCMFG_DEBUG("Writing per-frame group: "
+                        << DcmFGTypes::FGType2OFString((*groupIt).second->getType())
+                        << " for frame #" << frameNo);
+            OFCondition result = (*groupIt).second->write(*perFrameItem);
+            groupIt++;
+            if (result.bad())
+            {
+                DCMFG_ERROR("Error writing functional group for frame #" << frameNo << ": " << result.text());
+                m_errorMutex->lock();
+                *m_errorOccurred = result.condition(); // Store the error
+                m_errorMutex->unlock();
+                return;
+            }
+        }
+        // Lock the mutex before modifying shared data
+        m_perFrameResultItemsMutex->lock();
+        (*m_perFrameResultItems)[idx] = perFrameItem.release();
+        m_perFrameResultItemsMutex->unlock();
+    }
+}
+
+
+// ---------------------------------- ThreadedFGWReader ----------------------------------
+
+FGInterface::ThreadedFGReader::ThreadedFGReader()
+    : OFThread()
+    , m_perFrameItems(OFnullptr)
+    , m_frameResultGroups(OFnullptr)
+    , m_frameResultGroupsMutex(OFnullptr)
+    , m_startFrame(0)
+    , m_endFrame(0)
+    , m_errorMutex(OFnullptr)
+    , m_errorOccurred(OFnullptr)
+{
+}
+
+
+void FGInterface::ThreadedFGReader::init(OFVector<DcmItem*>* perFrameItems,
+                                         OFMutex* perFrameItemsMutex,
+                                         PerFrameGroups* frameResultGroups,
+                                         OFMutex* frameResultGroupsMutex,
+                                         Uint32 startFrame,
+                                         Uint32 endFrame,
+                                         OFMutex* errorMutex,
+                                         OFConditionConst* errorOccurred,
+                                         FGInterface* fgInterfacePtr)
+{
+    m_perFrameItems = perFrameItems;
+    m_perFrameItemsMutex = perFrameItemsMutex;
+    m_frameResultGroups = frameResultGroups;
+    m_frameResultGroupsMutex = frameResultGroupsMutex;
+    m_startFrame = startFrame;
+    m_endFrame = endFrame;
+    m_errorMutex = errorMutex;
+    m_errorOccurred = errorOccurred;
+    m_fgInterfacePtr = fgInterfacePtr;
+}
+
+FGInterface::ThreadedFGReader::~ThreadedFGReader()
+{
+    // Nothing to do here
+}
+
+
+void FGInterface::ThreadedFGReader::run()
+{
+    if (!m_perFrameItems || !m_frameResultGroups)
+    {
+        DCMFG_ERROR("ThreadedFGReader: Not properly initialized, cannot run.");
+        m_errorMutex->lock();
+        *m_errorOccurred = FG_EC_ParallelProcessingFailed;
+        m_errorMutex->unlock();
+        return;
+    }
+
+    // Iterate over all frames and read the functional groups
+    for (Uint32 idx = m_startFrame; idx < m_endFrame; ++idx)
+    {
+        Uint32 frameNo = idx;
+        // No need to lock for reading from m_perFrameItems, as each thread only reads its assigned range
+        if (frameNo >= m_perFrameItems->size())
+        {
+            DCMFG_ERROR("Frame index " << frameNo << " out of bounds for per-frame items vector");
+            m_errorMutex->lock();
+            *m_errorOccurred = FG_EC_ParallelProcessingFailed;
+            m_errorMutex->unlock();
+            return;
+        }
+        DcmItem* perFrameItem = (*m_perFrameItems)[frameNo];
+        if (!perFrameItem)
+        {
+            DCMFG_ERROR("No per-frame item found for frame #" << frameNo);
+            m_errorMutex->lock();
+            *m_errorOccurred = FG_EC_ParallelProcessingFailed; // Store the error
+            m_errorMutex->unlock();
+            return;
+        }
+
+        DCMFG_DEBUG("Reading per-frame groups for frame #" << frameNo);
+        // Create a new FunctionalGroups object to store the read groups
+        OFunique_ptr<FunctionalGroups> groupsOneFrame(new FunctionalGroups());
+        if (!groupsOneFrame)
+        {
+            DCMFG_ERROR("Memory exhausted while creating FunctionalGroups object for frame #" << frameNo);
+            m_errorMutex->lock();
+            *m_errorOccurred = EC_MemoryExhausted; // Store the error
+            m_errorMutex->unlock();
+            return;
+        }
+        // Read the functional groups from the per-frame item
+        // Remove parent item since otherwise the code will try to access the parent item
+        // to find the Specific Character Set, and this will crash if multiple threads
+        // try to access the same parent item.
+        DcmSequenceOfItems* perFrameFGSeq = OFstatic_cast(DcmSequenceOfItems*, perFrameItem->getParent());
+        perFrameItem->setParent(OFnullptr);
+        OFCondition result = m_fgInterfacePtr->readSingleFG(*perFrameItem, *groupsOneFrame);
+        perFrameItem->setParent(perFrameFGSeq); // Restore parent item
+        if (result.bad())
+        {
+            DCMFG_ERROR("Error reading functional groups for frame #" << frameNo << ": " << result.text());
+            m_errorMutex->lock();
+            *m_errorOccurred = result.condition(); // Store the error
+            m_errorMutex->unlock();
+            return;
+        }
+        // Lock the mutex before modifying shared data
+        m_frameResultGroupsMutex->lock();
+        // cast is safe since we check earlier that it is not
+        // larger than DcmFGTypes::DCMFG_MAX_FRAMES (2^32-1)
+        m_frameResultGroups->insert(OFMake_pair(frameNo, groupsOneFrame.release()));
+        m_frameResultGroupsMutex->unlock();
+        DCMFG_DEBUG("Finished reading functional groups for frame #" << frameNo);
+    }
+}
+
+
+
+// ----------------------------------- FGInterface -----------------------------------
+
 FGInterface::FGInterface()
     : m_shared()
     , m_perFrame()
     , m_checkOnWrite(OFTrue)
+    , m_numThreads(1) // Default to 1 thread
 {
 }
 
@@ -238,12 +445,36 @@ OFCondition FGInterface::readPerFrameFG(DcmItem& dataset)
     size_t numFrames = perFrame->card();
     if (numFrames == 0)
     {
-        DCMFG_WARN("No Item in Shared Functional Group Sequence but exactly one or more expected");
+        DCMFG_WARN("No Item in Per-Frame Functional Group Sequence but exactly one or more expected");
         return FG_EC_NoPerFrameFG;
     }
+    if (numFrames > DcmFGTypes::DCMFG_MAX_FRAMES)
+    {
+        DCMFG_ERROR("Too many items in Per-Frame Functional Group Sequence: " << numFrames
+                                << ", maximum is " << DcmFGTypes::DCMFG_MAX_FRAMES);
+        return FG_EC_TooManyItems;
+    }
 
+    // We want to either read sequentially or in parallel, depending on the number of threads.
+    // Cast is safe since e checked range above.
+    Uint32 threadsUsed = findAdequateNumberOfThreads(OFstatic_cast(Uint32, numFrames), m_numThreads);
+    if (threadsUsed > 1)
+    {
+        result = readPerFrameFGParallel(*perFrame, m_numThreads);
+    }
+    else
+    {
+        result = readPerFrameFGSequential(*perFrame);
+    }
+    return EC_Normal; // for now we always return EC_Normal...
+}
+
+
+OFCondition FGInterface::readPerFrameFGSequential(DcmSequenceOfItems& perFrameFGSeq)
+{
     /* Read functional groups for each item (one per frame) */
-    DcmItem* oneFrameItem = OFstatic_cast(DcmItem*, perFrame->nextInContainer(NULL));
+    OFCondition result;
+    DcmItem* oneFrameItem = OFstatic_cast(DcmItem*, perFrameFGSeq.nextInContainer(NULL));
     Uint32 count          = 0;
     while (oneFrameItem != NULL)
     {
@@ -271,12 +502,86 @@ OFCondition FGInterface::readPerFrameFG(DcmItem& dataset)
                 DCMFG_ERROR("Could not read functional groups for frame #" << count << ": " << result.text());
             }
         }
-        oneFrameItem = OFstatic_cast(DcmItem*, perFrame->nextInContainer(oneFrameItem));
+        oneFrameItem = OFstatic_cast(DcmItem*, perFrameFGSeq.nextInContainer(oneFrameItem));
         count++;
     }
     return EC_Normal; // for now we always return EC_Normal...
 }
 
+
+OFCondition FGInterface::readPerFrameFGParallel(DcmSequenceOfItems& perFrameFGSeq, const Uint32 numThreads)
+{
+    DCMFG_DEBUG("Reading per-frame functional groups in parallel using " << numThreads << " threads");
+    // Read functional groups for each item (one per frame)
+    OFCondition result;
+    size_t numFrames   = perFrameFGSeq.card();
+
+    // Create a vector to hold the functional groups for each frame and protect it with a mutex
+    PerFrameGroups& perFrameResultGroups = m_perFrame;
+    OFMutex perFrameResultGroupsMutex;
+
+    // Create a vector to hold the results of all threads, protected by a mutex
+    OFMutex perFrameInputMutex;
+    OFVector<DcmItem*> perFrameInputItems(numFrames, NULL);
+    // Fill the vector with items from the sequence
+    DcmItem* oneFrameItem = OFstatic_cast(DcmItem*, perFrameFGSeq.nextInContainer(NULL));
+    size_t count          = 0;
+    while (oneFrameItem != NULL)
+    {
+        // Store the item in the vector
+        perFrameInputItems[count] = oneFrameItem;
+        oneFrameItem = OFstatic_cast(DcmItem*, perFrameFGSeq.nextInContainer(oneFrameItem));
+        count++;
+    }
+
+    // Create a mutex for error handling
+    OFConditionConst errorOccurred = EC_Normal;
+    OFMutex errorMutex;
+
+    // Create and start threads
+    OFVector<ThreadedFGReader*> threads(numThreads);
+    // Range check on numFrames has been performed earlier so computation should be safe
+    Uint32 framesPerThread = OFstatic_cast(Uint32, (numFrames + numThreads - 1) / numThreads);
+    for (Uint32 i = 0; i < numThreads; ++i)
+    {
+        threads[i] = new ThreadedFGReader();
+        Uint32 startFrame = i * framesPerThread;
+        // numFrame is range-checked earlier
+        Uint32 endFrame = (startFrame + framesPerThread < numFrames) ? startFrame + framesPerThread : OFstatic_cast(Uint32, numFrames);
+
+        threads[i]->init(&perFrameInputItems, &perFrameInputMutex,
+                         &perFrameResultGroups, &perFrameResultGroupsMutex,
+                         startFrame,
+                         endFrame,
+                         &errorMutex, &errorOccurred, this);
+    }
+    // Start all threads
+    for (Uint32 i = 0; i < numThreads; ++i)
+    {
+        threads[i]->start();
+    }
+
+    // Wait for all threads to finish
+    for (Uint32 i = 0; i < numThreads; ++i)
+    {
+        threads[i]->join();
+        delete threads[i];
+        threads[i] = NULL;
+    }
+
+    // Check if any thread encountered an error
+    if (errorOccurred != EC_Normal)
+    {
+        DCMFG_ERROR("Error occurred while reading functional groups in parallel: " << OFCondition(errorOccurred).text());
+        return errorOccurred;
+    }
+
+    // Store the results in m_perFrame
+    return EC_Normal;
+}
+
+
+
 OFCondition FGInterface::readSingleFG(DcmItem& fgItem, FunctionalGroups& groups)
 {
     OFCondition result;
@@ -339,6 +644,8 @@ OFCondition FGInterface::write(DcmItem& dataset)
     // Write shared functional Groups
     OFCondition result = writeSharedFG(dataset);
 
+    DcmItem* seqItem;
+    dataset.findAndGetSequenceItem(DCM_SharedFunctionalGroupsSequence, seqItem);
     // Write per frame functional groups
     if (result.good())
         result = writePerFrameFG(dataset);
@@ -443,6 +750,23 @@ OFBool FGInterface::getCheckOnWrite()
     return m_checkOnWrite;
 }
 
+void FGInterface::setUseThreads(const Uint32 numThreads)
+{
+    if (numThreads > 0)
+    {
+        m_numThreads = numThreads;
+    }
+    else
+    {
+        m_numThreads = 1; // Fallback to single-threaded mode
+    }
+}
+
+Uint32 FGInterface::getUseThreads() const
+{
+    return m_numThreads;
+}
+
 FunctionalGroups* FGInterface::getOrCreatePerFrameGroups(const Uint32 frameNo)
 {
     OFMap<Uint32, FunctionalGroups*>::iterator it = m_perFrame.find(frameNo);
@@ -469,7 +793,45 @@ FunctionalGroups* FGInterface::getOrCreatePerFrameGroups(const Uint32 frameNo)
     return fg;
 }
 
+
 OFCondition FGInterface::writePerFrameFG(DcmItem& dataset)
+{
+    OFCondition result;
+
+    DCMFG_DEBUG("Writing per-frame functional groups");
+    result = dataset.insertEmptyElement(DCM_PerFrameFunctionalGroupsSequence, OFTrue); // start with empty sequence
+    if (result.bad())
+    {
+        DCMFG_ERROR("Could not create Per-frame Functional Groups Sequence");
+        return result;
+    }
+
+    /* Iterate over frames */
+    size_t numFrames = m_perFrame.size();
+    if (numFrames > DcmFGTypes::DCMFG_MAX_FRAMES)
+    {
+        DCMFG_ERROR("Too many frames in Per-frame Functional Groups: " << numFrames
+                                << ", maximum is " << DcmFGTypes::DCMFG_MAX_FRAMES);
+        return FG_EC_TooManyItems;
+    }
+
+    // Use parallel processing for writing functional groups, if desired and adequate.
+    // Cast is safe since we checked range above.
+    Uint32 threadsUsed = findAdequateNumberOfThreads(OFstatic_cast(Uint32, numFrames), m_numThreads);
+    if (threadsUsed > 1)
+    {
+        result = writePerFrameFGParallel(dataset, m_numThreads);
+    }
+    else
+    {
+        // Fallback to sequential processing for small datasets or single-threaded environment
+        result = writePerFrameFGSequential(dataset);
+    }
+
+    return result;
+}
+
+OFCondition FGInterface::writePerFrameFGSequential(DcmItem& dataset)
 {
     DCMFG_DEBUG("Writing per-frame functional groups");
     OFCondition result
@@ -509,6 +871,91 @@ OFCondition FGInterface::writePerFrameFG(DcmItem& dataset)
     return result;
 }
 
+
+OFCondition FGInterface::writePerFrameFGParallel(DcmItem& dataset, const Uint32 numThreads)
+{
+    DCMFG_DEBUG("Writing per-frame functional groups in parallel using " << numThreads << " threads");
+    OFConditionConst errorOccurred(EC_Normal);
+    OFMutex errorMutex;
+    OFMutex perFrameItemsMutex;
+
+    // Prepare a vector of frame numbers and their corresponding FunctionalGroups pointers.
+    // We need this to distribute the work across threads. Using the OFMap directly in threads
+    // could lead to data races and inconsistencies since each thread would invalidate the iterators
+    // being used in the other threads.
+    OFVector<OFPair<Uint32, FunctionalGroups*> > frameGroups;
+    frameGroups.reserve(m_perFrame.size());
+    for (OFMap<Uint32, FunctionalGroups*>::iterator it = m_perFrame.begin(); it != m_perFrame.end(); ++it)
+    {
+        frameGroups.push_back(OFMake_pair((*it).first, (*it).second));
+    }
+    // We check earlier that number of frames is not larger than max allowed
+    Uint32 numFrames = OFstatic_cast(Uint32, frameGroups.size());
+
+    // Prepare output vector for per-frame items
+    OFVector<DcmItem*> perFrameItems(numFrames, NULL);
+
+    // Thread pool
+    OFVector<ThreadedFGWriter*> threads;
+    threads.reserve(numThreads);
+
+    Uint32 framesPerThread = (numFrames + numThreads - 1) / numThreads;
+
+    for (Uint32 threadIndex = 0; threadIndex < numThreads; ++threadIndex)
+    {
+        Uint32 startFrame = threadIndex * framesPerThread;
+        Uint32 endFrame = (startFrame + framesPerThread < numFrames) ? startFrame + framesPerThread : numFrames;
+
+        ThreadedFGWriter* writer = new ThreadedFGWriter();
+        writer->init(&frameGroups, &perFrameItems, &perFrameItemsMutex, startFrame, endFrame, &errorOccurred, &errorMutex);
+        threads.push_back(writer);
+        writer->start(); // Start the thread
+    }
+
+    // Wait for all threads to complete
+    OFVector<ThreadedFGWriter*>::iterator thread = threads.begin();
+    while (thread != threads.end())
+    {
+        (*thread)->join();
+        delete (*thread); // Clean up the thread object
+        thread++;
+    }
+    threads.clear();
+
+    if (errorOccurred == EC_Normal)
+    {
+        DCMFG_DEBUG("All threads completed successfully, inserting per-frame items into the dataset");
+    }
+    else
+    {
+        DCMFG_ERROR("Error occurred in one or more threads: " << OFCondition(errorOccurred).text());
+        return OFCondition(errorOccurred);
+    }
+    // insert all per-frame items into the dataset
+    OFCondition result;
+    for (size_t idx = 0; idx < perFrameItems.size(); ++idx)
+    {
+        DcmItem* perFrameItem = perFrameItems[idx];
+        Uint32 frameNo = frameGroups[idx].first;
+        if (perFrameItem != NULL)
+        {
+            DCMFG_DEBUG("Inserting per-frame item for frame #" << frameNo);
+            result = dataset.insertSequenceItem(DCM_PerFrameFunctionalGroupsSequence, perFrameItem, OFstatic_cast(long, frameNo));
+            if (result.bad())
+            {
+                DCMFG_ERROR("Error inserting per-frame item for frame #" << frameNo << ": " << result.text());
+                break;
+            }
+        }
+        else
+        {
+            DCMFG_ERROR("Per-frame item for frame #" << frameNo << " is NULL, cannot insert into dataset");
+        }
+    }
+    return result; // Return the result of the last insertion
+}
+
+
 OFCondition FGInterface::writeSharedFG(DcmItem& dataset)
 {
     DCMFG_DEBUG("Writing shared functional groups");
@@ -524,7 +971,7 @@ OFCondition FGInterface::writeSharedFG(DcmItem& dataset)
         DCMFG_ERROR("Could not create Shared Functional Groups Sequence with single item");
         return result;
     }
-
+    DCMFG_DEBUG("Writing " << m_shared.size() << "  shared functional groups to item");
     FunctionalGroups::iterator it  = m_shared.begin();
     FunctionalGroups::iterator end = m_shared.end();
     while ((it != end) && result.good())
@@ -547,8 +994,6 @@ OFCondition FGInterface::insertPerFrame(const Uint32 frameNo, FGBase* group, con
     {
         if (replaceExisting)
         {
-            DCMFG_DEBUG("Replacing per-frame FG for frame: " << frameNo << ", type: "
-                                                             << DcmFGTypes::FGType2OFString(group->getType()));
             deletePerFrame(frameNo, group->getType());
         }
         else
@@ -604,6 +1049,40 @@ OFCondition FGInterface::convertSharedToPerFrame(const DcmFGTypes::E_FGType fgTy
     return result;
 }
 
+
+Uint32 FGInterface::findAdequateNumberOfThreads(const Uint32 numFrames, const Uint32 userThreadSetting)
+{
+    // If no threads are requested, we use one thread
+    if (userThreadSetting == 0)
+    {
+        DCMFG_DEBUG("No threads requested, using 1 thread by default.");
+        return 1;
+    }
+    // We should have at least 10 frames per thread, lower number of threads so
+    // that every thread has at least 10 frames to process.
+    Uint32 framesPerThread = numFrames / userThreadSetting;
+    if (framesPerThread < 10)
+    {
+        DCMFG_DEBUG("Requested number of threads (" << userThreadSetting
+                                                    << ") is too high for the number of frames (" << numFrames
+                                                    << "), reducing to a minimum of 10 frames per thread.");
+        // If the user requested more threads than we can use, we limit the number of threads
+        // to the number of frames divided by 10.
+        Uint32 numThreads = numFrames / 10;
+        if (numThreads < 1)
+        {
+            numThreads = 1; // At least one thread is required
+        }
+        return numThreads;
+    }
+    DCMFG_DEBUG("Using " << userThreadSetting << " threads for " << numFrames << " frames");
+
+    // If we have enough frames per thread, we can use the user setting
+    DCMFG_DEBUG("Using user-defined number of threads: " << userThreadSetting);
+    return userThreadSetting;
+}
+
+
 FGBase* FGInterface::get(const Uint32 frameNo, const DcmFGTypes::E_FGType fgType, OFBool& isPerFrame)
 {
     FGBase* group = m_shared.find(fgType);
@@ -628,7 +1107,7 @@ OFBool FGInterface::check()
     for (size_t frameCount = 0; frameCount < numFrames; frameCount++)
     {
         DCMFG_TRACE("Checking frame " << frameCount << "...");
-        // Every frame requires the FrameContent functional group, check "en passant"
+        // Most IODS require the FrameContent functional group, check "en passant"
         OFBool foundFrameContent                           = OFFalse;
         OFMap<Uint32, FunctionalGroups*>::iterator frameFG = m_perFrame.begin();
         OFMap<Uint32, FunctionalGroups*>::iterator end     = m_perFrame.end();
@@ -665,8 +1144,9 @@ OFBool FGInterface::check()
         }
         if (!foundFrameContent)
         {
-            DCMFG_ERROR("Frame Content Functional group missing for frame #" << frameCount);
-            numErrors++;
+            // TODO: This is an error for some IODs but not all (it used to be in earlier editions of the standard)
+            DCMFG_WARN("Frame Content Functional group missing for frame #" << frameCount);
+            // numErrors++;
         }
     }
 
index 71b44edd11f6fe9dd7e7a342b490a6f0152f09bd..d087b753f4e042ad2131ce0d93e88831cfc796bd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2019, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -64,6 +64,12 @@ OFCondition FGSegmentation::getReferencedSegmentNumber(Uint16& value, const unsi
 
 OFCondition FGSegmentation::setReferencedSegmentNumber(const Uint16& segmentNumber)
 {
+    if (segmentNumber == 0)
+    {
+        // Segment numbers start at 1, so 0 is invalid
+        DCMFG_ERROR("Segment Number must not be 0");
+        return FG_EC_InvalidData;
+    }
     return m_ReferencedSegmentNumber.putUint16(segmentNumber);
 }
 
index 1a3536688e2cb640f150e0e28d03c723fdeb4cfb..762a189f29c2032131ab52eafd7e2ed7fc1fb98d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -53,6 +53,7 @@ makeOFConditionConst(FG_EC_PixelDataTooLarge, OFM_dcmfg, 18, OF_error, "Pixel Da
 makeOFConditionConst(FG_EC_InconsistentConcatenationData, OFM_dcmfg, 19, OF_error, "Inconsistent Concatenation Data");
 makeOFConditionConst(FG_EC_ConcatenationComplete, OFM_dcmfg, 20, OF_error, "Concatenation Complete - no more data");
 makeOFConditionConst(FG_EC_UnsupportedPixelDataLayout, OFM_dcmfg, 21, OF_error, "Unsupported pixel data layout");
+makeOFConditionConst(FG_EC_ParallelProcessingFailed, OFM_dcmfg, 22, OF_error, "Parallel processing failed");
 
 OFString DcmFGTypes::FGType2OFString(const DcmFGTypes::E_FGType fgType)
 {
index 92b125b5f9b6d61d3e980bd751a5d8982442db53..4e887eda19f0ac48f23e2b1f2f189a384da40c47 100644 (file)
@@ -15,7 +15,7 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmfg_tests
 )
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcmfg_tests dcmfg dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(dcmfg_tests dcmfg)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmfg)
index 7e1d85a99b7f2788b14938260471adaf87e6985f..bceb29516fa53c341880163cafcfab44bf36626c 100644 (file)
@@ -59,7 +59,11 @@ t_concatenation_creator.o: t_concatenation_creator.cc \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
- ../include/dcmtk/dcmfg/fgdefine.h ../include/dcmtk/dcmfg/fgtypes.h \
+ ../include/dcmtk/dcmfg/fgdefine.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../include/dcmtk/dcmfg/fgtypes.h \
  ../../ofstd/include/dcmtk/ofstd/oftempf.h \
  ../../ofstd/include/dcmtk/ofstd/oftest.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
@@ -115,6 +119,9 @@ t_concatenation_loader.o: t_concatenation_loader.cc \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
@@ -125,11 +132,9 @@ t_concatenation_loader.o: t_concatenation_loader.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -537,40 +542,30 @@ t_ct_table_dynamics.o: t_ct_table_dynamics.cc \
 t_deriv_image.o: t_deriv_image.cc \
  ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmfg/fgderimg.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
- ../../ofstd/include/dcmtk/ofstd/ofcast.h \
- ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/oftraits.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../../ofstd/include/dcmtk/ofstd/oflimits.h \
- ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
  ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../oflog/include/dcmtk/oflog/config/defines.h \
  ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
  ../../oflog/include/dcmtk/oflog/loglevel.h \
  ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../oflog/include/dcmtk/oflog/tchar.h \
  ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
  ../../oflog/include/dcmtk/oflog/layout.h \
  ../../oflog/include/dcmtk/oflog/streams.h \
@@ -583,10 +578,16 @@ t_deriv_image.o: t_deriv_image.cc \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -594,24 +595,28 @@ t_deriv_image.o: t_deriv_image.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
- ../include/dcmtk/dcmfg/fgbase.h ../include/dcmtk/dcmfg/fgtypes.h \
- ../include/dcmtk/dcmfg/fgdefine.h \
+ ../include/dcmtk/dcmfg/fgtypes.h ../include/dcmtk/dcmfg/fgdefine.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
index 729261324ce5b53fd3c51b3f52da674d72a56d06..495407a8d6b9fae591d31a5c5781d4fcf461a718 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -93,7 +93,7 @@ OFTEST(dcmfg_concatenation_loader)
     // Scanning done, now load
 
     DcmFileFormat dcmff;
-    OFVector<DcmIODTypes::Frame*> frames;
+    OFVector<DcmIODTypes::FrameBase*> frames;
     result = cl.load("1.3.6.1.4.1.5962.1.7.70.2.1.1166562673.14401", dcmff.getDataset(), frames);
     OFCHECK(result.good());
     if (result.good())
@@ -402,7 +402,7 @@ static void prepare_dset_dump()
     DSET_DUMP += "        (0018,1210) SH [STANDARD]                               #   8, 1 ConvolutionKernel\n";
     DSET_DUMP += "        (0018,9315) CS [ITERATIVE]                              #  10, 1 ReconstructionAlgorithm\n";
     DSET_DUMP += "        (0018,9316) CS [SOFT_TISSUE]                            #  12, 1 ConvolutionKernelGroup\n";
-    DSET_DUMP += "        (0018,9319) FD 360                                      #   8, 1 ReconstructionAngle\n";
+    DSET_DUMP += "        (0018,9319) FD 360.00024414062494                       #   8, 1 ReconstructionAngle\n";
     DSET_DUMP += "        (0018,9320) SH [None]                                   #   4, 1 ImageFilter\n";
     DSET_DUMP += "        (0018,9322) FD 0.6347661018371581\\0.6347661018371581    #  16, 2 ReconstructionPixelSpacing\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
@@ -410,9 +410,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "    (0018,9321) SQ (Sequence with undefined length #=1)     # u/l, 1 CTExposureSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=5)         # u/l, 1 Item\n";
     DSET_DUMP += "        (0018,9323) CS [NONE]                                   #   4, 1 ExposureModulationType\n";
-    DSET_DUMP += "        (0018,9328) FD 1000                                     #   8, 1 ExposureTimeInms\n";
-    DSET_DUMP += "        (0018,9330) FD 230                                      #   8, 1 XRayTubeCurrentInmA\n";
-    DSET_DUMP += "        (0018,9332) FD 230                                      #   8, 1 ExposureInmAs\n";
+    DSET_DUMP += "        (0018,9328) FD 1000.0004882812499                       #   8, 1 ExposureTimeInms\n";
+    DSET_DUMP += "        (0018,9330) FD 230.00012207031247                       #   8, 1 XRayTubeCurrentInmA\n";
+    DSET_DUMP += "        (0018,9332) FD 230.00012207031247                       #   8, 1 ExposureInmAs\n";
     DSET_DUMP += "        (0018,9345) FD (no value available)                     #   0, 0 CTDIvol\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -479,8 +479,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-10.00000762939453 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-10.00000762939453 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-10.00000762939453 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-10.00000762939453 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -10.00000762939453                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -517,8 +517,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-17.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-17.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-17.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-17.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -17.00143432617187                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -555,9 +555,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-24.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-24.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -24.0029                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-24.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-24.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -24.002853393554684                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -593,9 +593,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-31.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-31.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -31.0043                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-31.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-31.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -31.004272460937496                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -631,8 +631,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-38.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-38.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-38.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-38.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -37.99575805664062                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -669,8 +669,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-45.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-45.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-45.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-45.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -44.99716186523437                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -707,8 +707,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-52.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-52.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-52.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-52.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -51.99859619140624                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -745,8 +745,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-59.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-59.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-59.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-59.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -59.00003051757812                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -783,8 +783,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-66.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-66.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-66.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-66.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -66.00146484374999                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -821,8 +821,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-73.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-73.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-73.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-73.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -73.00286865234374                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -859,8 +859,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-80.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-80.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-80.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-80.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -80.00433349609374                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -897,8 +897,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-87.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-87.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-87.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-87.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -86.99578857421874                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -935,8 +935,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-94.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-94.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-94.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-94.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -93.99719238281249                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -973,9 +973,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-101         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-101         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -100.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-101.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-101.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -100.99859619140624                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1011,9 +1011,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-108         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-108         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -108                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-108.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-108.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -108.00006103515624                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1049,9 +1049,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-115         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-115         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -115.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-115.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-115.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -115.00146484374999                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1087,9 +1087,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-122         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-122         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -122.003                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-122.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-122.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -122.00286865234374                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1125,9 +1125,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-129         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-129         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -129.004                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-129.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-129.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -129.00439453124997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1163,9 +1163,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-136         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-136         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -135.996                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-136.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-136.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -135.99584960937497                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1201,9 +1201,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-143         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-143         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -142.997                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-143.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-143.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -142.99719238281247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1239,9 +1239,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-150         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-150         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -149.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-150.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-150.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -149.99865722656247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1277,9 +1277,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-157         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-157         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -157                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-157.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-157.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -157.00012207031247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1315,9 +1315,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-164         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-164         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -164.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-164.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-164.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -164.00146484374997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1353,9 +1353,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-171         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-171         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -171.003                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-171.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-171.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -171.00292968749997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1391,9 +1391,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-178         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-178         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -178.004                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-178.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-178.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -178.00439453124997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1429,9 +1429,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-185         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-185         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -184.996                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-185.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-185.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -184.99584960937497                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1467,9 +1467,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-192         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-192         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -191.997                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-192.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-192.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -191.99719238281247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1505,9 +1505,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-199         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-199         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -198.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-199.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-199.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -198.99865722656247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1543,9 +1543,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-206         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-206         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -206                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-206.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-206.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -206.00012207031247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1581,9 +1581,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-213         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-213         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -213.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-213.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-213.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -213.00146484374997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1619,8 +1619,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-10.00000762939453 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-10.00000762939453 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-10.00000762939453 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-10.00000762939453 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -10.00000762939453                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1657,8 +1657,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-17.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-17.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-17.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-17.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -17.00143432617187                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1695,9 +1695,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-24.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-24.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -24.0029                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-24.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-24.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -24.002853393554684                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1733,9 +1733,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-31.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-31.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -31.0043                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-31.00001525878906 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-31.00001525878906 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -31.004272460937496                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -1771,8 +1771,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-38.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-38.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-38.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-38.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -37.99575805664062                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1809,8 +1809,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-45.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-45.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-45.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-45.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -44.99716186523437                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1847,8 +1847,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-52.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-52.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-52.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-52.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -51.99859619140624                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1885,8 +1885,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-59.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-59.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-59.00003051757812 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-59.00003051757812 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -59.00003051757812                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1923,8 +1923,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-66.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-66.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-66.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-66.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -66.00146484374999                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1961,8 +1961,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-73.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-73.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-73.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-73.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -73.00286865234374                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -1999,8 +1999,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-80.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-80.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-80.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-80.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -80.00433349609374                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -2037,8 +2037,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-87.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-87.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-87.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-87.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -86.99578857421874                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -2075,8 +2075,8 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-94.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-94.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-94.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-94.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
     DSET_DUMP += "        (0018,9327) FD -93.99719238281249                       #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
@@ -2113,9 +2113,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-101         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-101         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -100.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-101.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-101.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -100.99859619140624                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2151,9 +2151,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-108         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-108         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -108                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-108.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-108.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -108.00006103515624                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2189,9 +2189,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-115         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-115         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -115.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-115.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-115.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -115.00146484374999                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2227,9 +2227,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-122         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-122         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -122.003                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-122.00006103515624 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-122.00006103515624 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -122.00286865234374                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2265,9 +2265,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-129         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-129         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -129.004                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-129.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-129.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -129.00439453124997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2303,9 +2303,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-136         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-136         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -135.996                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-136.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-136.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -135.99584960937497                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2341,9 +2341,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-143         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-143         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -142.997                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-143.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-143.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -142.99719238281247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2379,9 +2379,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-150         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-150         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -149.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-150.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-150.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -149.99865722656247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2417,9 +2417,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-157         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-157         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -157                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-157.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-157.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -157.00012207031247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2455,9 +2455,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-164         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-164         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -164.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-164.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-164.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -164.00146484374997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2493,9 +2493,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-171         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-171         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -171.003                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-171.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-171.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -171.00292968749997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2531,9 +2531,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-178         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-178         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -178.004                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-178.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-178.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -178.00439453124997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2569,9 +2569,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-185         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-185         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -184.996                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-185.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-185.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -184.99584960937497                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2607,9 +2607,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-192         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-192         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -191.997                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-192.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-192.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -191.99719238281247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2645,9 +2645,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-199         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-199         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -198.999                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-199.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-199.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -198.99865722656247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2683,9 +2683,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-206         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-206         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -206                                     #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-206.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-206.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -206.00012207031247                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
@@ -2721,9 +2721,9 @@ static void prepare_dset_dump()
     DSET_DUMP += "  (fffe,e000) na (Item with undefined length #=4)         # u/l, 1 Item\n";
     DSET_DUMP += "    (0018,9326) SQ (Sequence with undefined length #=1)     # u/l, 1 CTPositionSequence\n";
     DSET_DUMP += "      (fffe,e000) na (Item with undefined length #=3)         # u/l, 1 Item\n";
-    DSET_DUMP += "        (0018,9313) FD 3.08271\\-0.3172872066497802\\-213         #  24, 3 DataCollectionCenterPatient\n";
-    DSET_DUMP += "        (0018,9318) FD 3.08271\\-0.3172872066497802\\-213         #  24, 3 ReconstructionTargetCenterPatient\n";
-    DSET_DUMP += "        (0018,9327) FD -213.001                                 #   8, 1 TablePosition\n";
+    DSET_DUMP += "        (0018,9313) FD 3.0827140808105464\\-0.3172872066497802\\-213.00012207031247 #  24, 3 DataCollectionCenterPatient\n";
+    DSET_DUMP += "        (0018,9318) FD 3.0827140808105464\\-0.3172872066497802\\-213.00012207031247 #  24, 3 ReconstructionTargetCenterPatient\n";
+    DSET_DUMP += "        (0018,9327) FD -213.00146484374997                      #   8, 1 TablePosition\n";
     DSET_DUMP += "      (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem\n";
     DSET_DUMP += "    (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem\n";
     DSET_DUMP += "    (0018,9341) SQ (Sequence with undefined length #=2)     # u/l, 1 ContrastBolusUsageSequence\n";
index 00437a68b6da0d571f187f1618f109b32f3d3390..faec81038d32b680f107cd0b9d671affe6b0e126 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2022-2024, OFFIS e.V.
+ *  Copyright (C) 2022-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -46,4 +46,5 @@ OFTEST(dcmfg_fgbase_fgunknown)
     FGUnknown* fg_copy = OFstatic_cast(FGUnknown*, fg.clone());
     OFCHECK(fg_copy != NULL);
     OFCHECK(fg.compare(*fg_copy) == 0);
+    delete fg_copy;
 }
index c6238c2e3789da6316a171f6420f048cec2c7b4b..50d6e09adbe3231541e0cd29cd1bd3c2bedc8645 100644 (file)
@@ -23,6 +23,6 @@ the same command line parameters, and more.
 
 \section dcm2pnm_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index e9c56d83046a17de9543900da9bad1b7608e6723..51ca82081316059055eed4d99b49fee0e375cdd2 100644 (file)
@@ -372,6 +372,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmicmp_copyright COPYRIGHT
 
-Copyright (C) 2018-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2018-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 0bc03eb31bbe6aa67d36d2a8fc9c4d2811b58a2e..f77ffbd2e191c486798082b246539a1a9ac042d2 100644 (file)
@@ -284,6 +284,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmquant_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 404802dff2d20355710a0881684d7c3345c64571..15e2803440aa402b46f0a5b57313b5a95e73f0cd 100644 (file)
@@ -266,6 +266,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmscale_copyright COPYRIGHT
 
-Copyright (C) 2002-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2002-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 0a11f290e519d6210dcf0d0a80ed540ed17b428b..450bc11e2f9ace5ae03bdf348cc940ece3e6ac7b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2016, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -88,7 +88,7 @@ class DiColorMonoTemplate
     {
         if (pixel != NULL)
         {
-            this->Data = new T[this->Count];
+            this->Data = new (std::nothrow) T[this->Count];
             if (this->Data != NULL)
             {
                 const T *r = pixel[0];
index d812d169ee318bea6713945b176f822859a902ec..0ece5329b84ed1dba6815c950e4ee468704f81a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2016, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -125,16 +125,9 @@ class DiColorPixelTemplate
      */
     virtual ~DiColorPixelTemplate()
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
-        /* use a non-throwing delete (if available) */
         operator delete[] (Data[0], std::nothrow);
         operator delete[] (Data[1], std::nothrow);
         operator delete[] (Data[2], std::nothrow);
-#else
-        delete[] Data[0];
-        delete[] Data[1];
-        delete[] Data[2];
-#endif
     }
 
     /** get integer representation
@@ -365,7 +358,7 @@ class DiColorPixelTemplate
                         data = new Uint32[count];
                     if (data != NULL)
                     {
-                        Uint32 *q = OFstatic_cast(Uint32 *, data);
+                        Uint8 *q = OFstatic_cast(Uint8 *, data);
                         if (fromBits == toBits)
                         {
                             /* copy pixel data as is */
@@ -373,10 +366,11 @@ class DiColorPixelTemplate
                             {
                                 for (x = width; x != 0; x--)
                                 {
-                                    /* normal sample order: 0-R-G-B */
-                                    *(q++) = (OFstatic_cast(Uint32, *(r++)) << 16) |
-                                             (OFstatic_cast(Uint32, *(g++)) << 8) |
-                                             OFstatic_cast(Uint32, *(b++));
+                                    /* sample order: B-G-R-0 */
+                                    *(q++) = OFstatic_cast(Uint8, *(b++));
+                                    *(q++) = OFstatic_cast(Uint8, *(g++));
+                                    *(q++) = OFstatic_cast(Uint8, *(r++));
+                                    *(q++) = 0;
                                 }
                                 r += nextRow; g += nextRow; b += nextRow;           // go backwards if 'upsideDown'
                             }
@@ -393,10 +387,11 @@ class DiColorPixelTemplate
                                 {
                                     for (x = width; x != 0; x--)
                                     {
-                                        /* normal sample order: 0-R-G-B */
-                                        *(q++) = (OFstatic_cast(Uint32, *(r++) * gradient2) << 16) |
-                                                 (OFstatic_cast(Uint32, *(g++) * gradient2) << 8) |
-                                                 OFstatic_cast(Uint32, *(b++) * gradient2);
+                                        /* sample order: B-G-R-0 */
+                                        *(q++) = OFstatic_cast(Uint8, *(b++) * gradient2);
+                                        *(q++) = OFstatic_cast(Uint8, *(g++) * gradient2);
+                                        *(q++) = OFstatic_cast(Uint8, *(r++) * gradient2);
+                                        *(q++) = 0;
                                     }
                                     r += nextRow; g += nextRow; b += nextRow;       // go backwards if 'upsideDown'
                                 }
@@ -405,10 +400,11 @@ class DiColorPixelTemplate
                                 {
                                     for (x = width; x != 0; x--)
                                     {
-                                        /* normal sample order: 0-R-G-B */
-                                        *(q++) = (OFstatic_cast(Uint32, OFstatic_cast(double, *(r++)) * gradient1) << 16) |
-                                                 (OFstatic_cast(Uint32, OFstatic_cast(double, *(g++)) * gradient1) << 8) |
-                                                 OFstatic_cast(Uint32, OFstatic_cast(double, *(b++)) * gradient1);
+                                        /* sample order: B-G-R-0 */
+                                        *(q++) = OFstatic_cast(Uint8, OFstatic_cast(double, *(b++)) * gradient1);
+                                        *(q++) = OFstatic_cast(Uint8, OFstatic_cast(double, *(g++)) * gradient1);
+                                        *(q++) = OFstatic_cast(Uint8, OFstatic_cast(double, *(r++)) * gradient1);
+                                        *(q++) = 0;
                                     }
                                     r += nextRow; g += nextRow; b += nextRow;       // go backwards if 'upsideDown'
                                 }
@@ -422,10 +418,11 @@ class DiColorPixelTemplate
                             {
                                 for (x = width; x != 0; x--)
                                 {
-                                    /* normal sample order: 0-R-G-B */
-                                    *(q++) = (OFstatic_cast(Uint32, *(r++) >> shift) << 16) |
-                                             (OFstatic_cast(Uint32, *(g++) >> shift) << 8) |
-                                             OFstatic_cast(Uint32, *(b++) >> shift);
+                                    /* sample order: B-G-R-0 */
+                                    *(q++) = OFstatic_cast(Uint8, *(b++) >> shift);
+                                    *(q++) = OFstatic_cast(Uint8, *(g++) >> shift);
+                                    *(q++) = OFstatic_cast(Uint8, *(r++) >> shift);
+                                    *(q++) = 0;
                                 }
                                 r += nextRow; g += nextRow; b += nextRow;           // go backwards if 'upsideDown'
                             }
@@ -556,25 +553,17 @@ class DiColorPixelTemplate
             /* allocate data buffer for the 3 planes */
             for (int j = 0; j < 3; j++)
             {
-#ifdef HAVE_STD__NOTHROW
                 /* use a non-throwing new here (if available) because the allocated buffer can be huge */
                 Data[j] = new (std::nothrow) T[Count];
-#else
-                /* make sure that the pointer is set to NULL in case of error */
-                try
-                {
-                    Data[j] = new T[Count];
-                }
-                catch (STD_NAMESPACE bad_alloc const &)
-                {
-                    Data[j] = NULL;
-                }
-#endif
                 if (Data[j] != NULL)
                 {
                     /* erase empty part of the buffer (=blacken the background) */
                     if (InputCount < Count)
-                        OFBitmanipTemplate<T>::zeroMem(Data[j] + InputCount, Count - InputCount);
+                    {
+                        const size_t count = (Count - InputCount);
+                        DCMIMAGE_TRACE("filing empty part of the intermediate pixel data (" << count << " pixels) of plane " << j << " with value = 0");
+                        OFBitmanipTemplate<T>::zeroMem(Data[j] + InputCount, count);
+                    }
                 } else {
                     DCMIMAGE_DEBUG("cannot allocate memory buffer for 'Data[" << j << "]' in DiColorPixelTemplate::Init()");
                     result = 0;     // at least one buffer could not be allocated!
index e787ab24915de16be1903fc4af172c50469a53fa..c7b13b1f7005b6a946b174853a92b41b8b0abb5b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmimage/dicdefin.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 /* needed e.g. on Solaris for definition of size_t */
 #include <sys/types.h>
-#endif
 END_EXTERN_C
 
 /** helper structure for class DcmQuantPixelBoxArray.
index 965572977ef21963c60f68f2a90b1cce0d838a4e..3fcb7e287901f8aec08bc0fa8a583f223f6122a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2016, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -24,6 +24,7 @@
 #define DIYBRPXT_H
 
 #include "dcmtk/config/osconfig.h"
+#include "dcmtk/ofstd/ofbmanip.h"
 
 #include "dcmtk/dcmimage/dicopxt.h"
 #include "dcmtk/dcmimgle/diinpx.h"  /* gcc 3.4 needs this */
@@ -90,179 +91,190 @@ class DiYBRPixelTemplate
             // use the number of input pixels derived from the length of the 'PixelData'
             // attribute), but not more than the size of the intermediate buffer
             const unsigned long count = (this->InputCount < this->Count) ? this->InputCount : this->Count;
-            if (rgb)    /* convert to RGB model */
+            // make sure that there is sufficient input data (for planar pixel data)
+            if (!this->PlanarConfiguration || (count >= planeSize))
             {
-                T2 *r = this->Data[0];
-                T2 *g = this->Data[1];
-                T2 *b = this->Data[2];
-                const T2 maxvalue = OFstatic_cast(T2, DicomImageClass::maxval(bits));
-                DiPixelRepresentationTemplate<T1> rep;
-                if (bits == 8 && !rep.isSigned())          // only for unsigned 8 bit
+                if (rgb)    /* convert to RGB model */
                 {
-                    Sint16 rcr_tab[256];
-                    Sint16 gcb_tab[256];
-                    Sint16 gcr_tab[256];
-                    Sint16 bcb_tab[256];
-                    const double r_const = 0.7010 * OFstatic_cast(double, maxvalue);
-                    const double g_const = 0.5291 * OFstatic_cast(double, maxvalue);
-                    const double b_const = 0.8859 * OFstatic_cast(double, maxvalue);
-                    unsigned long l;
-                    for (l = 0; l < 256; ++l)
+                    T2 *r = this->Data[0];
+                    T2 *g = this->Data[1];
+                    T2 *b = this->Data[2];
+                    const T2 maxvalue = OFstatic_cast(T2, DicomImageClass::maxval(bits));
+                    DiPixelRepresentationTemplate<T1> rep;
+                    if (bits == 8 && !rep.isSigned())          // only for unsigned 8 bit
                     {
-                        rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * OFstatic_cast(double, l) - r_const);
-                        gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * OFstatic_cast(double, l));
-                        gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * OFstatic_cast(double, l) - g_const);
-                        bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * OFstatic_cast(double, l) - b_const);
-                    }
-                    Sint32 sr;
-                    Sint32 sg;
-                    Sint32 sb;
-                    if (this->PlanarConfiguration)
-                    {
-/*
-                        const T1 *y = pixel;
-                        const T1 *cb = y + this->InputCount;
-                        const T1 *cr = cb + this->InputCount;
-                        for (i = count; i != 0; --i, ++y, ++cb, ++cr)
+                        Sint16 rcr_tab[256];
+                        Sint16 gcb_tab[256];
+                        Sint16 gcr_tab[256];
+                        Sint16 bcb_tab[256];
+                        const double r_const = 0.7010 * OFstatic_cast(double, maxvalue);
+                        const double g_const = 0.5291 * OFstatic_cast(double, maxvalue);
+                        const double b_const = 0.8859 * OFstatic_cast(double, maxvalue);
+                        unsigned long l;
+                        for (l = 0; l < 256; ++l)
                         {
-                            sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[*cr]);
-                            sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]);
-                            sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[*cb]);
-                            *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
-                            *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
-                            *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
+                            rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * OFstatic_cast(double, l) - r_const);
+                            gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * OFstatic_cast(double, l));
+                            gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * OFstatic_cast(double, l) - g_const);
+                            bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * OFstatic_cast(double, l) - b_const);
                         }
+                        Sint32 sr;
+                        Sint32 sg;
+                        Sint32 sb;
+                        if (this->PlanarConfiguration)
+                        {
+/*
+                            const T1 *y = pixel;
+                            const T1 *cb = y + this->InputCount;
+                            const T1 *cr = cb + this->InputCount;
+                            for (i = count; i != 0; --i, ++y, ++cb, ++cr)
+                            {
+                                sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[*cr]);
+                                sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]);
+                                sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[*cb]);
+                                *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
+                                *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
+                                *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
+                            }
 */
-                        const T1 *y = pixel;
-                        const T1 *cb = y + planeSize;
-                        const T1 *cr = cb + planeSize;
-                        unsigned long i = count;
-                        while (i != 0)
+                            const T1 *y = pixel;
+                            const T1 *cb = y + planeSize;
+                            const T1 *cr = cb + planeSize;
+                            unsigned long i = count;
+                            while (i != 0)
+                            {
+                                /* convert a single frame */
+                                for (l = planeSize; (l != 0) && (i != 0); --l, --i, ++y, ++cb, ++cr)
+                                {
+                                    const Sint32 yValue = *y;
+                                    /* conversion to unsigned integer needed for gcc 14 on Solaris */
+                                    const unsigned int cbValue = *cb;
+                                    const unsigned int crValue = *cr;
+                                    sr = yValue + rcr_tab[crValue];
+                                    sg = yValue - gcb_tab[cbValue] - gcr_tab[crValue];
+                                    sb = yValue + bcb_tab[cbValue];
+                                    *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
+                                    *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
+                                    *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
+                                }
+                                /* jump to next frame start (skip 2 planes) */
+                                y += 2 * planeSize;
+                                cb += 2 * planeSize;
+                                cr += 2 * planeSize;
+                            }
+                        }
+                        else
                         {
-                            /* convert a single frame */
-                            for (l = planeSize; (l != 0) && (i != 0); --l, --i, ++y, ++cb, ++cr)
+                            const T1 *p = pixel;
+                            unsigned long i;
+                            for (i = count; i != 0; --i)
                             {
-                                sr = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, *cr)]);
-                                sg = OFstatic_cast(Sint32, *y) - OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, *cb)]) - OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, *cr)]);
-                                sb = OFstatic_cast(Sint32, *y) + OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, *cb)]);
+                                const Sint32 yValue = *(p++);
+                                /* conversion to unsigned integer needed for gcc 14 on Solaris */
+                                const unsigned int cbValue = *(p++);
+                                const unsigned int crValue = *(p++);
+                                sr = yValue + rcr_tab[crValue];
+                                sg = yValue - gcb_tab[cbValue] - gcr_tab[crValue];
+                                sb = yValue + bcb_tab[cbValue];
                                 *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
                                 *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
                                 *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
                             }
-                            /* jump to next frame start (skip 2 planes) */
-                            y += 2 * planeSize;
-                            cb += 2 * planeSize;
-                            cr += 2 * planeSize;
                         }
                     }
                     else
                     {
-                        const T1 *p = pixel;
-                        T1 y;
-                        T1 cb;
-                        T1 cr;
-                        unsigned long i;
-                        for (i = count; i != 0; --i)
+                        if (this->PlanarConfiguration)
+                        {
+/*
+                            const T1 *y = pixel;
+                            const T1 *cb = y + this->InputCount;
+                            const T1 *cr = cb + this->InputCount;
+                            for (i = count; i != 0; --i)
+                                convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset),
+                                    removeSign(*(cr++), offset), maxvalue);
+*/
+                            unsigned long l;
+                            unsigned long i = count;
+                            const T1 *y = pixel;
+                            const T1 *cb = y + planeSize;
+                            const T1 *cr = cb + planeSize;
+                            while (i != 0)
+                            {
+                                /* convert a single frame */
+                                for (l = planeSize; (l != 0) && (i != 0); --l, --i)
+                                {
+                                    const T2 yValue = removeSign(*(y++), offset);
+                                    const T2 cbValue = removeSign(*(cb++), offset);
+                                    const T2 crValue = removeSign(*(cr++), offset);
+                                    convertValue(*(r++), *(g++), *(b++), yValue, cbValue, crValue, maxvalue);
+                                }
+                                /* jump to next frame start (skip 2 planes) */
+                                y += 2 * planeSize;
+                                cb += 2 * planeSize;
+                                cr += 2 * planeSize;
+                            }
+                        }
+                        else
                         {
-                            y  = *(p++);
-                            cb = *(p++);
-                            cr = *(p++);
-                            sr = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, cr)]);
-                            sg = OFstatic_cast(Sint32, y) - OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, cb)]) - OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, cr)]);
-                            sb = OFstatic_cast(Sint32, y) + OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, cb)]);
-                            *(r++) = (sr < 0) ? 0 : (sr > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
-                            *(g++) = (sg < 0) ? 0 : (sg > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
-                            *(b++) = (sb < 0) ? 0 : (sb > OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
+                            const T1 *p = pixel;
+                            unsigned long i;
+                            for (i = count; i != 0; --i)
+                            {
+                                const T2 yValue = removeSign(*(p++), offset);
+                                const T2 cbValue = removeSign(*(p++), offset);
+                                const T2 crValue = removeSign(*(p++), offset);
+                                convertValue(*(r++), *(g++), *(b++), yValue, cbValue, crValue, maxvalue);
+                            }
                         }
                     }
-                }
-                else
-                {
+                } else {    /* retain YCbCr model */
+                    const T1 *p = pixel;
                     if (this->PlanarConfiguration)
                     {
 /*
-                        const T1 *y = pixel;
-                        const T1 *cb = y + this->InputCount;
-                        const T1 *cr = cb + this->InputCount;
-                        for (i = count; i != 0; --i)
-                            convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset),
-                                removeSign(*(cr++), offset), maxvalue);
+                        T2 *q;
+                        // number of pixels to be skipped (only applicable if 'PixelData' contains more
+                        // pixels than expected)
+                        const unsigned long skip = (this->InputCount > this->Count) ? (this->InputCount - this->Count) : 0;
+                        for (int j = 0; j < 3; ++j)
+                        {
+                            q = this->Data[j];
+                            for (i = count; i != 0; --i)
+                                *(q++) = removeSign(*(p++), offset);
+                            // skip to beginning of next plane
+                            p += skip;
+                        }
 */
                         unsigned long l;
-                        unsigned long i = count;
-                        const T1 *y = pixel;
-                        const T1 *cb = y + planeSize;
-                        const T1 *cr = cb + planeSize;
-                        while (i != 0)
+                        unsigned long i = 0;
+                        while (i < count)
                         {
-                            /* convert a single frame */
-                            for (l = planeSize; (l != 0) && (i != 0); --l, --i)
+                            /* store current pixel index */
+                            const unsigned long iStart = i;
+                            for (int j = 0; j < 3; ++j)
                             {
-                                convertValue(*(r++), *(g++), *(b++), removeSign(*(y++), offset), removeSign(*(cb++), offset),
-                                    removeSign(*(cr++), offset), maxvalue);
+                                /* convert a single plane */
+                                for (l = planeSize, i = iStart; (l != 0) && (i < count); --l, ++i)
+                                    this->Data[j][i] = removeSign(*(p++), offset);
                             }
-                            /* jump to next frame start (skip 2 planes) */
-                            y += 2 * planeSize;
-                            cb += 2 * planeSize;
-                            cr += 2 * planeSize;
                         }
                     }
                     else
                     {
-                        const T1 *p = pixel;
-                        T2 y;
-                        T2 cb;
-                        T2 cr;
+                        int j;
                         unsigned long i;
-                        for (i = count; i != 0; --i)
-                        {
-                            y = removeSign(*(p++), offset);
-                            cb = removeSign(*(p++), offset);
-                            cr = removeSign(*(p++), offset);
-                            convertValue(*(r++), *(g++), *(b++), y, cb, cr, maxvalue);
-                        }
-                    }
-                }
-            } else {    /* retain YCbCr model */
-                const T1 *p = pixel;
-                if (this->PlanarConfiguration)
-                {
-/*
-                    T2 *q;
-                    // number of pixels to be skipped (only applicable if 'PixelData' contains more
-                    // pixels than expected)
-                    const unsigned long skip = (this->InputCount > this->Count) ? (this->InputCount - this->Count) : 0;
-                    for (int j = 0; j < 3; ++j)
-                    {
-                        q = this->Data[j];
-                        for (i = count; i != 0; --i)
-                            *(q++) = removeSign(*(p++), offset);
-                        // skip to beginning of next plane
-                        p += skip;
-                    }
-*/
-                    unsigned long l;
-                    unsigned long i = 0;
-                    while (i < count)
-                    {
-                        /* store current pixel index */
-                        const unsigned long iStart = i;
-                        for (int j = 0; j < 3; ++j)
-                        {
-                            /* convert a single plane */
-                            for (l = planeSize, i = iStart; (l != 0) && (i < count); --l, ++i)
-                                this->Data[j][i] = removeSign(*(p++), offset);
-                        }
+                        for (i = 0; i < count; ++i)                             /* for all pixel ... */
+                            for (j = 0; j < 3; ++j)
+                                this->Data[j][i] = removeSign(*(p++), offset);  /* ... copy planes */
                     }
                 }
-                else
-                {
-                    int j;
-                    unsigned long i;
-                    for (i = 0; i < count; ++i)                             /* for all pixel ... */
-                        for (j = 0; j < 3; ++j)
-                            this->Data[j][i] = removeSign(*(p++), offset);  /* ... copy planes */
-                }
+            } else {
+                // do not process the input data, as it is too short
+                DCMIMAGE_WARN("input data is too short, filling the complete image with black pixels");
+                // erase empty part of the buffer (that has not been "blackened" yet)
+                for (int j = 0; j < 3; ++j)
+                    OFBitmanipTemplate<T2>::zeroMem(this->Data[j], count);
             }
         }
     }
index 5cd88f556bf500d0f87535fe07503a6183f25a06..fb169f06ddc92c005c651fae23a04acc8e5419d1 100644 (file)
@@ -223,13 +223,14 @@ diargimg.o: diargimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/restrict.def \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipxrept.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diinpx.h \
  ../include/dcmtk/dcmimage/diqttype.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h
 dicmyimg.o: dicmyimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
@@ -495,9 +496,21 @@ dicopx.o: dicopx.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diobjcou.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diinpx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
@@ -505,19 +518,8 @@ dicopx.o: dicopx.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -719,6 +721,7 @@ dipalimg.o: dipalimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/restrict.def \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipxrept.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diinpx.h \
  ../include/dcmtk/dcmimage/diqttype.h
@@ -1043,6 +1046,8 @@ diqthash.o: diqthash.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didispfn.h
@@ -1143,6 +1148,8 @@ diquant.o: diquant.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didispfn.h \
@@ -1156,8 +1163,6 @@ diquant.o: diquant.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixel.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpobw.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
 diregist.o: diregist.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -1249,12 +1254,13 @@ diregist.o: diregist.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h
 dirgbimg.o: dirgbimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
@@ -1406,10 +1412,11 @@ diybrimg.o: diybrimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimage/dicopx.h ../include/dcmtk/dcmimage/dilogger.h \
  ../include/dcmtk/dcmimage/dicdefin.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
- ../include/dcmtk/dcmimage/diybrpxt.h ../include/dcmtk/dcmimage/dicopxt.h \
+ ../include/dcmtk/dcmimage/diybrpxt.h \
  ../../ofstd/include/dcmtk/ofstd/ofbmanip.h \
  ../../ofstd/include/dcmtk/ofstd/diag/stringop.def \
  ../../ofstd/include/dcmtk/ofstd/diag/restrict.def \
+ ../include/dcmtk/dcmimage/dicopxt.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipxrept.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diinpx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didocu.h \
index c8904411e9217f93c8e599e900789a9749e42483..00f9946077e1b81a38f9681fd1801bfa16bb4d0b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -37,6 +37,9 @@ BEGIN_EXTERN_C
 #endif
 END_EXTERN_C
 
+#if TIFFLIB_VERSION < 20050912
+#error TIFF library versions prior to 3.7.4 are not supported by DCMTK
+#endif
 
 DiTIFFPlugin::DiTIFFPlugin()
 : DiPluginFormat()
@@ -63,27 +66,27 @@ int DiTIFFPlugin::write(
     int stream_fd = fileno(stream);
 
 
-#ifdef HAVE_WINDOWS_H
-
-#if TIFFLIB_VERSION < 20050912
-#error TIFF library versions prior to 3.7.4 are not supported by DCMTK on Win32 - critical API change!
+#ifdef _WIN32
+
+    /* On Windows, TIFFFdOpen() expects a Windows HANDLE (which is a pointer
+     * type) instead of a file descriptor, but passes the file descriptor as an
+     * int.  Despite HANDLE being a 64-bit type on Win64 and int being 32-bit,
+     * this is apparently safe, because Win64 guarantees to only use 32-bit
+     * handles, for interoperability reasons, as documented here:
+     *
+     *   https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
+     *
+     * Therefore, we use _get_osfhandle() to access the HANDLE underlying the
+     * file descriptor.
+     */
+
+#ifdef __CYGWIN__
+    stream_fd = OFstatic_cast(int, get_osfhandle(stream_fd));
+#else
+    stream_fd = OFstatic_cast(int, _get_osfhandle(stream_fd));
 #endif
 
-/* Older versions of libtiff expected a Win32 HANDLE when compiled on Windows
- * instead of a file descriptor. The code below was needed to make that work.
- * Libtiff version 3.7.4 and newer are known to use a file descriptor instead,
- * but it is not completely clear at which libtiff release the API change happened.
- *
- * #ifdef __CYGWIN__
- *   stream_fd = OFstatic_cast(int, get_osfhandle(stream_fd));
- * #else
- *   stream_fd =OFstatic_cast(int, _get_osfhandle(stream_fd));
- * #endif
- */
-
-#elif TIFFLIB_VERSION < 20041016
-#error TIFF library versions prior to 3.7.0 are not supported by DCMTK - TIFFCleanup is missing!
-#endif
+#endif /* _WIN32 */
 
     /* create bitmap with 8 bits per sample */
     void *data = OFconst_cast(void *, image->getOutputData(frame, 8 /*bits*/, 0 /*planar*/));
@@ -161,9 +164,10 @@ int DiTIFFPlugin::write(
             offset += bytesperrow;
           }
           TIFFFlushData(tif);
+
           /* Clean up internal structures and free memory.
            * However, the file will be closed by the caller, therefore
-           * TIFFClose(tif) is not called.
+           * TIFFClose() is not called.
            */
           TIFFCleanup(tif);
         }
@@ -183,16 +187,19 @@ void DiTIFFPlugin::setCompressionType(DiTIFFCompression ctype)
   compressionType = ctype;
 }
 
+
 void DiTIFFPlugin::setLZWPredictor(DiTIFFLZWPredictor pred)
 {
   predictor = pred;
 }
 
+
 void DiTIFFPlugin::setRowsPerStrip(unsigned long rows)
 {
   rowsPerStrip = rows;
 }
 
+
 OFString DiTIFFPlugin::getLibraryVersionString()
 {
     /* use first line only, omit copyright information */
index f49392d7151d3e389b1aa4119bcd2a59d34dbace..14cdb26f095ed31e9c35c36c48dd2f6533fc8844 100644 (file)
@@ -98,27 +98,20 @@ OFCondition DcmQuantColorTable::computeHistogram(
 
   // compute initial maxval
   maxval = OFstatic_cast(DcmQuantComponent, -1);
-  DcmQuantColorHashTable *htable = NULL;
 
   // attempt to make a histogram of the colors, unclustered.
   // If at first we don't succeed, lower maxval to increase color
   // coherence and try again.  This will eventually terminate.
-  OFBool done = OFFalse;
-  while (! done)
+  do
   {
-    htable = new DcmQuantColorHashTable();
-    numColors = htable->addToHashTable(image, maxval, maxcolors);
-    if (numColors > 0) done = OFTrue;
-    else
-    {
-      delete htable;
+      DcmQuantColorHashTable htable;
+      if (htable.addToHashTable(image, maxval, maxcolors) > 0)
+      {
+          numColors = htable.createHistogram(array);
+          return EC_Normal;
+      }
       maxval = maxval/2;
-    }
-  }
-
-  numColors = htable->createHistogram(array);
-  delete htable;
-  return EC_Normal;
+  } while (OFTrue);
 }
 
 
index 69740a74069a862bd27c4258a98de555ec04fc78..5bd573f3e5c4b40492ccf571b59498382e2cc31b 100644 (file)
@@ -196,6 +196,6 @@ longish and confusing command lines (an example is provided in file
 
 \section dcmdspfn_copyright COPYRIGHT
 
-Copyright (C) 1999-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1999-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index fd07ca0ce9a1303bf3e731c38f5e2c8046c54dc0..3ead26a506f7595d28785748e8e9b85b1744a66c 100644 (file)
@@ -56,6 +56,6 @@ sample characteristics file monitors, cameras, printers and scanners.
 
 \section dcod2lum_copyright COPYRIGHT
 
-Copyright (C) 2002-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2002-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 2973544112a9b4543d79ce66d6c3c973d70f10fb..5a1958626db14cd8b2796d4618eb43fcebefddc5 100644 (file)
@@ -54,6 +54,6 @@ Barten's model (including GSDF).
 
 \section dconvlum_copyright COPYRIGHT
 
-Copyright (C) 1999-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1999-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 6a37c2d7fefcf0e3a1193adc60a777417b38655a..76c5de979de4bf489bf2e0cd90c7087876ee31c6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2021, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -166,12 +166,7 @@ class DiInputPixelTemplate
      */
     virtual ~DiInputPixelTemplate()
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
-        /* use a non-throwing delete (if available) */
         operator delete[] (Data, std::nothrow);
-#else
-        delete[] Data;
-#endif
     }
 
 #include DCMTK_DIAGNOSTIC_PUSH
@@ -189,6 +184,7 @@ class DiInputPixelTemplate
             T2 *p = Data;
             unsigned long i;
             const double absrange = getAbsMaxRange();
+            const double absmin = getAbsMinimum();
             const unsigned long ocnt = (absrange <= 10000000.0) ? OFstatic_cast(unsigned long, absrange) : 0 /* no LUT */;
             Uint8 *lut = NULL;
             if ((sizeof(T2) <= 2) && (ocnt > 0) && (Count > 3 * ocnt)) // optimization criteria
@@ -198,7 +194,7 @@ class DiInputPixelTemplate
                 {
                     DCMIMGLE_DEBUG("using optimized routine with additional LUT");
                     OFBitmanipTemplate<Uint8>::zeroMem(lut, ocnt);
-                    Uint8 *q = lut - OFstatic_cast(T2, getAbsMinimum());
+                    Uint8 *q = lut - OFstatic_cast(T2, absmin);
                     for (i = Count; i != 0; --i)                       // fill lookup table
                         *(q + *(p++)) = 1;
                     q = lut;
@@ -206,7 +202,7 @@ class DiInputPixelTemplate
                     {
                         if (*(q++) != 0)
                         {
-                            MinValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i) + getAbsMinimum());
+                            MinValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i) + absmin);
                             break;
                         }
                     }
@@ -215,7 +211,7 @@ class DiInputPixelTemplate
                     {
                         if (*(--q) != 0)
                         {
-                            MaxValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + getAbsMinimum());
+                            MaxValue[0] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + absmin);
                             break;
                         }
                     }
@@ -226,24 +222,24 @@ class DiInputPixelTemplate
                     } else {                                           // calculate min/max for selected range
                         OFBitmanipTemplate<Uint8>::zeroMem(lut, ocnt);
                         p = Data + PixelStart;
-                        q = lut - OFstatic_cast(T2, getAbsMinimum());
-                        for (i = PixelCount; i != 0; --i)                  // fill lookup table
+                        q = lut - OFstatic_cast(T2, absmin);
+                        for (i = PixelCount; i != 0; --i)              // fill lookup table
                             *(q + *(p++)) = 1;
                         q = lut;
-                        for (i = 0; i < ocnt; ++i)                         // search for minimum
+                        for (i = 0; i < ocnt; ++i)                     // search for minimum
                         {
                             if (*(q++) != 0)
                             {
-                                MinValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i) + getAbsMinimum());
+                                MinValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i) + absmin);
                                 break;
                             }
                         }
                         q = lut + ocnt;
-                        for (i = ocnt; i != 0; --i)                         // search for maximum
+                        for (i = ocnt; i != 0; --i)                    // search for maximum
                         {
                             if (*(--q) != 0)
                             {
-                                MaxValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + getAbsMinimum());
+                                MaxValue[1] = OFstatic_cast(T2, OFstatic_cast(double, i - 1) + absmin);
                                 break;
                             }
                         }
@@ -380,33 +376,22 @@ class DiInputPixelTemplate
             /* Bits Allocated is always a multiple of 8 (see above), same for bits of T1 */
             const Uint32 byteFactor = bitsAllocated / 8;
             const Uint32 bytes_T1 = bitsof_T1 / 8;
-            const Uint32 count_T1 = (byteFactor == bytes_T1) ? PixelCount : (PixelCount * byteFactor + bytes_T1 - 1) / bytes_T1;
+            const Uint32 count_T1 = OFstatic_cast(Uint32, (byteFactor == bytes_T1) ? PixelCount : (PixelCount * byteFactor + bytes_T1 - 1) / bytes_T1);
 #ifdef DEBUG
             DCMIMGLE_TRACE("PixelCount: " << PixelCount << ", byteFactor: " << byteFactor << ", bytes_T1: " << bytes_T1 << ", count_T1: " << count_T1);
 #endif
             /* allocate temporary buffer, even number of bytes required for getUncompressedFrame() */
             const Uint32 extraByte = ((sizeof(T1) == 1) && (count_T1 & 1)) ? 1 : 0;
-#ifdef HAVE_STD__NOTHROW
+
             /* use a non-throwing new here (if available) because the allocated buffer can be huge */
             pixel = new (std::nothrow) T1[count_T1 + extraByte];
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                pixel = new T1[count_T1 + extraByte];
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                pixel = NULL;
-            }
-#endif
             if (pixel != NULL)
             {
                 if (uncompressed)
                 {
                     DCMIMGLE_DEBUG("using partial read access to uncompressed pixel data");
-                    const Uint32 offset = PixelStart * byteFactor;
-                    const Uint32 bufSize = PixelCount * byteFactor;
+                    const Uint32 offset = OFstatic_cast(Uint32, PixelStart * byteFactor);
+                    const Uint32 bufSize = OFstatic_cast(Uint32, PixelCount * byteFactor);
                     const OFCondition status = pixelData->getPartialValue(pixel, offset, bufSize, fileCache);
                     if (status.good())
                     {
@@ -420,13 +405,13 @@ class DiInputPixelTemplate
                     DCMIMGLE_DEBUG("using partial read access to compressed pixel data");
                     OFCondition status = EC_IllegalCall;
                     OFString decompressedColorModel;
-                    const Uint32 fsize = FrameSize * byteFactor;
+                    const Uint32 fsize = OFstatic_cast(Uint32, FrameSize * byteFactor);
                     for (Uint32 frame = 0; frame < NumberOfFrames; ++frame)
                     {
                         /* make sure that the buffer always has an even number of bytes as required for getUncompressedFrame() */
                         const Uint32 bufSize = (fsize & 1) ? fsize + 1 : fsize;
-                        status = pixelData->getUncompressedFrame(document->getDataset(), FirstFrame + frame, fragment,
-                            OFreinterpret_cast(Uint8 *, pixel) + lengthBytes, bufSize, decompressedColorModel, fileCache);
+                        status = pixelData->getUncompressedFrame(document->getDataset(), OFstatic_cast(Uint32, FirstFrame + frame),
+                            fragment, OFreinterpret_cast(Uint8 *, pixel) + lengthBytes, bufSize, decompressedColorModel, fileCache);
                         if (status.good())
                         {
                             DCMIMGLE_TRACE("successfully decompressed frame " << FirstFrame + frame);
@@ -455,27 +440,16 @@ class DiInputPixelTemplate
         }
         if ((pixel != NULL) && (lengthBytes > 0))
         {
-            const Uint32 length_T1 = lengthBytes / sizeof(T1);
+            const Uint32 length_T1 = OFstatic_cast(Uint32, lengthBytes / sizeof(T1));
             /* need to split 'length' in order to avoid integer overflow for large pixel data */
             const Uint32 length_B1 = lengthBytes / bitsAllocated;
             const Uint32 length_B2 = lengthBytes % bitsAllocated;
 //          # old code: Count = ((lengthBytes * 8) + bitsAllocated - 1) / bitsAllocated;
             Count = 8 * length_B1 + (8 * length_B2 + bitsAllocated - 1) / bitsAllocated;
             unsigned long i;
-#ifdef HAVE_STD__NOTHROW
+
             /* use a non-throwing new here (if available) because the allocated buffer can be huge */
             Data = new (std::nothrow) T2[Count];
-#else
-            /* make sure that the pointer is set to NULL in case of error */
-            try
-            {
-                Data = new T2[Count];
-            }
-            catch (STD_NAMESPACE bad_alloc const &)
-            {
-                Data = NULL;
-            }
-#endif
             if (Data != NULL)
             {
                 DCMIMGLE_TRACE("Input length: " << lengthBytes << " bytes, Pixel count: " << Count
@@ -500,7 +474,7 @@ class DiInputPixelTemplate
                         T2 smask = 0;
                         for (i = bitsStored; i < bitsof_T2; ++i)
                             smask |= OFstatic_cast(T2, 1 << i);
-                        const Uint16 shift = highBit + 1 - bitsStored;
+                        const Uint16 shift = OFstatic_cast(Uint16, highBit + 1 - bitsStored);
                         if (shift == 0)
                         {
                             DCMIMGLE_DEBUG("convert input pixel data: case 1b (mask & sign)");
@@ -561,7 +535,7 @@ class DiInputPixelTemplate
                         T2 smask = 0;
                         for (i = bitsStored; i < bitsof_T2; ++i)
                             smask |= OFstatic_cast(T2, 1 << i);
-                        const Uint16 shift = highBit + 1 - bitsStored;
+                        const Uint16 shift = OFstatic_cast(Uint16, highBit + 1 - bitsStored);
                         for (i = length_T1; i != 0; --i)
                         {
                             value = *(p++) >> shift;
@@ -571,6 +545,22 @@ class DiInputPixelTemplate
                                 value >>= bitsAllocated;
                             }
                         }
+                        /* check whether there are any remaining pixel values to be processed */
+                        const signed int rest = OFstatic_cast(int, Count - length_T1 * times);
+                        if (rest > 0)
+                        {
+                            /* usually, there is only a single final pixel value */
+                            if (rest == 1)
+                                DCMIMGLE_TRACE("  there is still " << rest << " pixel value to be processed, so let's do it");
+                            else
+                                DCMIMGLE_TRACE("  there are still " << rest << " pixel values to be processed, so let's do it");
+                            value = *(p++) >> shift;
+                            for (j = OFstatic_cast(Uint16, rest); j != 0; --j)
+                            {
+                                *(q++) = expandSign(OFstatic_cast(T2, value & mask), sign, smask);
+                                value >>= bitsAllocated;
+                            }
+                        }
                     }
                 }
                 else if ((bitsof_T1 < bitsAllocated) && (bitsAllocated % bitsof_T1 == 0)    // case 3: multiplicand of 8/16
@@ -603,7 +593,7 @@ class DiInputPixelTemplate
                     T1 mask[bitsof_T1];
                     mask[0] = 1;
                     for (i = 1; i < bitsof_T1; ++i)
-                        mask[i] = (mask[i - 1] << 1) | 1;
+                        mask[i] = OFstatic_cast(T1, (mask[i - 1] << 1) | 1);
                     T2 smask = 0;
                     for (i = bitsStored; i < bitsof_T2; ++i)
                         smask |= OFstatic_cast(T2, 1 << i);
@@ -643,6 +633,13 @@ class DiInputPixelTemplate
                             skip -= times * bitsof_T1;
                         }
                     }
+                    /* fill the remaining entry (if any) with the smallest value that is possible */
+                    if (q < Data + Count)
+                    {
+                        DCMIMGLE_TRACE("not enough data, filling last entry of input buffer with value = " << getAbsMinimum());
+                        *q = OFstatic_cast(T2, getAbsMinimum());
+                    }
+
                 }
             } else
                 DCMIMGLE_DEBUG("cannot allocate memory buffer for 'Data' in DiInputPixelTemplate::convert()");
@@ -653,12 +650,7 @@ class DiInputPixelTemplate
         if (deletePixel)
         {
             /* delete temporary buffer */
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
-            /* use a non-throwing delete (if available) */
             operator delete[] (pixel, std::nothrow);
-#else
-            delete[] pixel;
-#endif
         }
     }
 
index 4383f350c80ee7722dbbe4d1e26f72de2cc00b3e..ce49e29743bff88c58bd92c8bb88d9a3b3a2277c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2011, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,6 +26,7 @@
 #include "dcmtk/config/osconfig.h"
 #include "dcmtk/dcmdata/dctagkey.h"
 
+#include "dcmtk/dcmdata/dcvrobow.h"
 #include "dcmtk/dcmimgle/dibaslut.h"
 #include "dcmtk/dcmimgle/diobjcou.h"
 
@@ -107,6 +108,23 @@ class DCMTK_DCMIMGLE_EXPORT DiLookupTable
                   const signed long first = -1,
                   EI_Status *status = NULL);
 
+
+    /** constructor
+     *
+     ** @param  data         element containing the LUT data (must be of VR=OW)
+     *  @param  descriptor   element containing the LUT descriptor
+     *  @param  explanation  element containing the LUT explanation (optional)
+     *  @param  descripMode  mode specifying the use of the bits per table entry value
+     *  @param  first        expected value for "first input value mapped" (optional)
+     *  @param  status       pointer to image status variable (optional)
+     */
+    DiLookupTable(const DcmOtherByteOtherWord &data,
+                  const DcmUnsignedShort &descriptor,
+                  const DcmLongString *explanation = NULL,
+                  const EL_BitsPerTableEntry descripMode = ELM_UseValue,
+                  const signed long first = -1,
+                  EI_Status *status = NULL);
+
     /** constructor
      *
      ** @param  buffer  pointer to array with LUT entries
@@ -169,6 +187,19 @@ class DCMTK_DCMIMGLE_EXPORT DiLookupTable
     int compareLUT(const DcmUnsignedShort &data,
                    const DcmUnsignedShort &descriptor);
 
+    /** compares current LUT with specified LUT
+     *
+     ** @param  data        element containing the LUT data (must be of VR=OW)
+     *  @param  descriptor  element containing the LUT descriptor
+     *
+     ** @return true if LUTs are not equal (1 = invalid LUT / memory error,
+     *                                      2 = descriptor differs,
+     *                                      3 = data differs)
+     *          false (0) otherwise
+     */
+    int compareLUT(const DcmOtherByteOtherWord &data,
+                   const DcmUnsignedShort &descriptor);
+
 
     /** compares current LUT with specified LUT
      *
@@ -207,6 +238,24 @@ class DCMTK_DCMIMGLE_EXPORT DiLookupTable
               const EL_BitsPerTableEntry descripMode = ELM_UseValue,
               EI_Status *status = NULL);
 
+    /** initialize lookup table
+     *
+     ** @param  data         array containing the LUT data
+     *  @param  count        number of entries in LUT data array
+     *  @param  descriptor   element containing the LUT descriptor
+     *  @param  explanation  element containing the LUT explanation (optional)
+     *  @param  descripMode  mode specifying the use of the bits per table entry value
+     *  @param  first        expected value for "first input value mapped" (optional)
+     *  @param  status       pointer to image status variable (optional)
+     */
+    void Init(const Uint16 *data,
+              const unsigned long count,
+              const DcmUnsignedShort &descriptor,
+              const DcmLongString *explanation = NULL,
+              const EL_BitsPerTableEntry descripMode = ELM_UseValue,
+              const signed long first = -1,
+              EI_Status *status = NULL);
+
     /** check (and possibly correct) lookup table for consistency
      *
      ** @param  count        number of LUT entries
index 7172ea3a841236cf6771154e653a70c2ebbc72f0..4e3020e6d217feaad83c6583eb660b651daa1467 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2010, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -82,7 +82,7 @@ class DiMonoCopyTemplate
     {
         if (pixel != NULL)
         {
-            this->Data = new T[this->getCount()];
+            this->Data = new (std::nothrow) T[this->getCount()];
             if (this->Data != NULL)
                 OFBitmanipTemplate<T>::copyMem(pixel, this->Data, this->getCount());
         }
index bf626c3b97b496284c423c6881905f2ecb7534d4..505ffa55714683ecf49f1bb4ad37e17738117783 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2011, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -95,7 +95,7 @@ class DiMonoFlipTemplate
     {
         if (pixel != NULL)
         {
-            this->Data = new T[this->getCount()];
+            this->Data = new (std::nothrow) T[this->getCount()];
             if (this->Data != NULL)
             {
                 if (horz && vert)
index e746a68b9145e8314c0913d17295cc86b68d771a..15f929eae72406f4f7c2825d62af03c4fc6addd5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2021, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -28,6 +28,7 @@
 #include "dcmtk/ofstd/ofbmanip.h"
 #include "dcmtk/ofstd/ofcast.h"
 #include "dcmtk/ofstd/ofdiag.h"      /* for DCMTK_DIAGNOSTIC macros */
+#include "dcmtk/ofstd/oflimits.h"    /* for OFnumeric_limits<> */
 
 #include "dcmtk/dcmimgle/dimopxt.h"
 #include "dcmtk/dcmimgle/diinpx.h"
@@ -55,16 +56,16 @@ class DiMonoInputPixelTemplate
                              DiMonoModality *modality)
       : DiMonoPixelTemplate<T3>(pixel, modality)
     {
-        if ((pixel != NULL) && (this->Count > 0))
+        if ((pixel != NULL) && (this->Modality != NULL) && (this->Count > 0))
         {
             // check whether to apply any modality transform
-            if ((this->Modality != NULL) && this->Modality->hasLookupTable() && (bitsof(T1) <= MAX_TABLE_ENTRY_SIZE))
+            if (this->Modality->hasLookupTable() && (bitsof(T1) <= MAX_TABLE_ENTRY_SIZE))
             {
                 modlut(pixel);
                 // ignore modality LUT min/max values since the image does not necessarily have to use all LUT entries
                 this->determineMinMax();
             }
-            else if ((this->Modality != NULL) && this->Modality->hasRescaling())
+            else if (this->Modality->hasRescaling())
             {
                 rescale(pixel, this->Modality->getRescaleSlope(), this->Modality->getRescaleIntercept());
                 this->determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue()));
@@ -72,9 +73,16 @@ class DiMonoInputPixelTemplate
                 rescale(pixel);                     // "copy" or reference pixel data
                 this->determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue()));
             }
-            /* erase empty part of the buffer (= blacken the background) */
+            /* erase empty part of the buffer */
             if ((this->Data != NULL) && (this->InputCount < this->Count))
-                OFBitmanipTemplate<T3>::zeroMem(this->Data + this->InputCount, this->Count - this->InputCount);
+            {
+                /* that means, fill the background with the smallest value that is possible */
+                const T3 minOut = OFnumeric_limits<T3>::min();
+                const T3 background = (this->Modality->getAbsMinimum() < OFstatic_cast(double, minOut)) ? minOut : OFstatic_cast(T3, this->Modality->getAbsMinimum());
+                const size_t count = (this->Count - this->InputCount);
+                DCMIMGLE_DEBUG("filing empty part of the intermediate pixel data (" << count << " pixels) with value = " << OFstatic_cast(double, background));
+                OFBitmanipTemplate<T3>::setMem(this->Data + this->InputCount, background, count);
+            }
         }
     }
 
@@ -134,7 +142,7 @@ class DiMonoInputPixelTemplate
                     this->Data = OFstatic_cast(T3 *, input->getDataPtr());
                     input->removeDataReference();              // avoid double deletion
                 } else
-                    this->Data = new T3[this->Count];
+                    this->Data = new (std::nothrow) T3[this->Count];
                 if (this->Data != NULL)
                 {
                     DCMIMGLE_DEBUG("applying modality transformation with LUT (" << mlut->getCount() << " entries)");
@@ -206,7 +214,7 @@ class DiMonoInputPixelTemplate
                 this->Data = OFstatic_cast(T3 *, input->getDataPtr());
                 input->removeDataReference();              // avoid double deletion
             } else
-                this->Data = new T3[this->Count];
+                this->Data = new (std::nothrow) T3[this->Count];
             if (this->Data != NULL)
             {
                 T3 *q = this->Data;
index 532ee3a068666c6f53d4a74c4fbce73fdec2eb02..cf6fc8f4ca89ceb57381bbeff9d19528d3553b39 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2016, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -60,20 +60,9 @@ class DiMonoPixelTemplate
         MaxValue[0] = 0;
         MaxValue[1] = 0;
         // allocate buffer of given size
-#ifdef HAVE_STD__NOTHROW
+
         /* use a non-throwing new here (if available) because the allocated buffer can be huge */
         Data = new (std::nothrow) T[Count];
-#else
-        /* make sure that the pointer is set to NULL in case of error */
-        try
-        {
-            Data = new T[Count];
-        }
-        catch (STD_NAMESPACE bad_alloc const &)
-        {
-            Data = NULL;
-        }
-#endif
         if (Data == NULL)
             DCMIMGLE_DEBUG("cannot allocate memory buffer for 'Data' in DiMonoPixelTemplate constructor");
     }
@@ -114,12 +103,7 @@ class DiMonoPixelTemplate
      */
     virtual ~DiMonoPixelTemplate()
     {
-#if defined(HAVE_STD__NOTHROW) && defined(HAVE_NOTHROW_DELETE)
-        /* use a non-throwing delete (if available) */
         operator delete[] (Data, std::nothrow);
-#else
-        delete[] Data;
-#endif
     }
 
     /** get integer representation
index c496956941064ab5c6e152da92695e59b6eac8be..1229adc5f23b1fc26724950b7706131ff35276da 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2011, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -94,7 +94,7 @@ class DiMonoRotateTemplate
     {
         if (pixel != NULL)
         {
-            this->Data = new T[DiMonoPixelTemplate<T>::getCount()];
+            this->Data = new (std::nothrow) T[DiMonoPixelTemplate<T>::getCount()];
             if (this->Data != NULL)
             {
                 if (degree == 90)
index a437b8186f3a8f5b4e04102bc11f1097feeb5237..c49fe7a564d5c4ee270ac05c5d4414ff0963895a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2011, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -112,7 +112,7 @@ class DiMonoScaleTemplate
     {
         if (pixel != NULL)
         {
-            this->Data = new T[this->getCount()];
+            this->Data = new (std::nothrow) T[this->getCount()];
             if (this->Data != NULL)
             {
                 const T value = OFstatic_cast(T, OFstatic_cast(double, DicomImageClass::maxval(bits)) *
index 47f4ce87018622bef435f9361612ab047feb905a..74ecc7fadae9af3e46d6389f8fd5eec00b78735d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2018, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -55,8 +55,7 @@ extern DCMTK_DCMIMGLE_EXPORT OFLogger DCM_dcmimgleLogger;
 
 /** @name configuration flags
  */
-
-//@{
+///@{
 
 /// compatibility with old ACR-NEMA images
 const unsigned long CIF_AcrNemaCompatibility         = 0x0000001;
@@ -98,7 +97,8 @@ const unsigned long CIF_DecompressCompletePixelData  = 0x0000800;
 
 /// never access embedded overlays since this requires to load and uncompress the complete pixel data
 const unsigned long CIF_NeverAccessEmbeddedOverlays  = 0x0001000;
-//@}
+
+///@}
 
 
 // / true color color mode (for monochrome images only)
index 8a4c4d1d38b6913c9047840d190c61ff3886c84f..01b83d1c6db4a6188073f215d2a060f7ee4af028 100644 (file)
@@ -66,6 +66,8 @@ dcmimage.o: dcmimage.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -77,7 +79,6 @@ dcmimage.o: dcmimage.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/dimo1img.h ../include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmimgle/diregbas.h \
  ../include/dcmtk/dcmimgle/diplugin.h
@@ -661,13 +662,14 @@ diluptab.o: diluptab.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/diutils.h \
+ ../include/dcmtk/dcmimgle/didefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofbmanip.h \
  ../../ofstd/include/dcmtk/ofstd/diag/stringop.def \
  ../../ofstd/include/dcmtk/ofstd/diag/restrict.def \
  ../include/dcmtk/dcmimgle/diluptab.h \
- ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/diutils.h \
- ../include/dcmtk/dcmimgle/didefine.h \
  ../include/dcmtk/dcmimgle/diobjcou.h ../include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h
@@ -739,6 +741,8 @@ dimo1img.o: dimo1img.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h
 dimo2img.o: dimo2img.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -809,6 +813,8 @@ dimo2img.o: dimo2img.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h
 dimoimg.o: dimoimg.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -879,6 +885,8 @@ dimoimg.o: dimoimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -899,7 +907,6 @@ dimoimg.o: dimoimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../include/dcmtk/dcmimgle/diregbas.h
 dimoimg3.o: dimoimg3.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -970,6 +977,8 @@ dimoimg3.o: dimoimg3.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h \
  ../include/dcmtk/dcmimgle/dimoipxt.h \
@@ -1049,6 +1058,8 @@ dimoimg4.o: dimoimg4.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h \
  ../include/dcmtk/dcmimgle/dimoipxt.h \
@@ -1128,6 +1139,8 @@ dimoimg5.o: dimoimg5.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h \
  ../include/dcmtk/dcmimgle/dimoipxt.h \
@@ -1156,7 +1169,16 @@ dimomod.o: dimomod.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
- ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/diutils.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
  ../../oflog/include/dcmtk/oflog/config.h \
@@ -1182,29 +1204,20 @@ dimomod.o: dimomod.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/didefine.h \
- ../include/dcmtk/dcmimgle/diobjcou.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmimgle/didocu.h \
- ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../include/dcmtk/dcmimgle/diobjcou.h ../include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
- ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
- ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
- ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -1253,9 +1266,22 @@ dimoopx.o: dimoopx.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../include/dcmtk/dcmimgle/dibaslut.h \
- ../include/dcmtk/dcmimgle/diobjcou.h \
- ../../ofstd/include/dcmtk/ofstd/ofthread.h
+ ../include/dcmtk/dcmimgle/diobjcou.h
 dimopx.o: dimopx.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/dimopx.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
@@ -1299,10 +1325,23 @@ dimopx.o: dimopx.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
- ../include/dcmtk/dcmimgle/dibaslut.h \
- ../include/dcmtk/dcmimgle/diobjcou.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../include/dcmtk/dcmimgle/diinpx.h ../include/dcmtk/dcmimgle/dimoopx.h
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../include/dcmtk/dcmimgle/dibaslut.h \
+ ../include/dcmtk/dcmimgle/diobjcou.h ../include/dcmtk/dcmimgle/diinpx.h \
+ ../include/dcmtk/dcmimgle/dimoopx.h
 diovdat.o: diovdat.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
@@ -1491,6 +1530,8 @@ diovlimg.o: diovlimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/diovpln.h ../include/dcmtk/dcmimgle/diutils.h \
  ../include/dcmtk/dcmimgle/dimopx.h ../include/dcmtk/dcmimgle/dipixel.h \
  ../include/dcmtk/dcmimgle/dimomod.h ../include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../include/dcmtk/dcmimgle/dibaslut.h ../include/dcmtk/dcmimgle/dimoopx.h \
  ../include/dcmtk/dcmimgle/didispfn.h ../include/dcmtk/dcmimgle/dimopxt.h \
  ../../ofstd/include/dcmtk/ofstd/ofbmanip.h \
@@ -1499,7 +1540,6 @@ diovlimg.o: diovlimg.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmimgle/dipxrept.h ../include/dcmtk/dcmimgle/didocu.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h
 diovpln.o: diovpln.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
index bc395a2792ad75500a4425aafdfaf95f047bd1db..ed107264c41de8f51972ae71ae775ce73448d67c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -210,6 +210,7 @@ void DicomImage::Init()
                         *(q++) = c;
                 }
                 *q = '\0';                                          // end of C string
+                DCMIMGLE_DEBUG("filtered version of 'PhotometricInterpretation' = " << OFSTRING_GUARD(cstr));
                 while ((pin->Name != NULL) && (strcmp(pin->Name, cstr) != 0))
                     ++pin;
                 delete[] cstr;
index 1c5e64cc69d328de2b5bdc2d2f5a97574921003c..13830fbc48d657a193da729387e374d912d193d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2021, OFFIS e.V.
+ *  Copyright (C) 1999-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -167,6 +167,8 @@ int DiCIELABLUT::createLUT(const Uint16 *ddl_tab,
                 {
                     if (Count == ddl_cnt)                   // check whether CIELAB LUT fits exactly to DISPLAY file
                     {
+                        /* use the standard "C" locale for proper decimal point */
+                        const STD_NAMESPACE locale oldLocale = stream->imbue(STD_NAMESPACE locale("C"));
                         for (i = 0; i < ddl_cnt; ++i)
                         {
                             (*stream) << ddl_tab[i];                               // DDL
@@ -183,6 +185,8 @@ int DiCIELABLUT::createLUT(const Uint16 *ddl_tab,
                             }
                             (*stream) << OFendl;
                         }
+                        /* reset locale */
+                        stream->imbue(oldLocale);
                     } else {
                         DCMIMGLE_WARN("can't write curve data, wrong DISPLAY file or CIELAB LUT");
                     }
index a0db6ec973ef5dd769e6fc31bf577bb22d3c9dba..584fac758ce08b3f4050b76b9cc2ba6fa92be9d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -175,7 +175,12 @@ void DiDocument::convertPixelData()
                 status = PixelData->getDecompressedColorModel(OFstatic_cast(DcmItem *, Object), PhotometricInterpretation);
                 if (status.bad())
                 {
-                    DCMIMGLE_ERROR("can't determine 'PhotometricInterpretation' of decompressed image");
+                    if (Flags & CIF_AcrNemaCompatibility)
+                    {
+                        DCMIMGLE_WARN("can't determine 'PhotometricInterpretation' of decompressed image "
+                            << "... assuming MONOCHROME2 (ACR-NEMA compatibility)");
+                    } else
+                        DCMIMGLE_ERROR("can't determine 'PhotometricInterpretation' of decompressed image");
                     DCMIMGLE_DEBUG("DcmPixelData::getDecompressedColorModel() returned: " << status.text());
                 }
             } else {
index d1aae66876d82d5957cf1c82772aad3571da82e5..fa931657365a93940c711888c6dae0e5895087f6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2021, OFFIS e.V.
+ *  Copyright (C) 1999-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -181,6 +181,8 @@ int DiGSDFLUT::createLUT(const Uint16 *ddl_tab,
                             {
                                 if (Count == ddl_cnt)                   // check whether GSDF LUT fits exactly to DISPLAY file
                                 {
+                                    /* use the standard "C" locale for proper decimal point */
+                                    const STD_NAMESPACE locale oldLocale = stream->imbue(STD_NAMESPACE locale("C"));
                                     for (i = 0; i < ddl_cnt; ++i)
                                     {
                                         (*stream) << ddl_tab[i];                               // DDL
@@ -197,6 +199,8 @@ int DiGSDFLUT::createLUT(const Uint16 *ddl_tab,
                                         }
                                         (*stream) << OFendl;
                                     }
+                                    /* reset locale */
+                                    stream->imbue(oldLocale);
                                 } else {
                                     DCMIMGLE_WARN("can't write curve data, wrong DISPLAY file or GSDF LUT");
                                 }
index 480235e3b542c5bcbcccf50d92aac178a17a4e5f..0f52587581968d99098a4749c44be52da5423c11 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -549,12 +549,18 @@ void DiImage::convertPixelData()
     {
         const unsigned long fsize = OFstatic_cast(unsigned long, Rows) * OFstatic_cast(unsigned long, Columns) *
             OFstatic_cast(unsigned long, SamplesPerPixel);
-        if ((BitsAllocated < 1) || (BitsStored < 1) || (BitsAllocated < BitsStored) ||
-            (BitsStored > OFstatic_cast(Uint16, HighBit + 1)))
+        if ((BitsAllocated < 1) || (BitsStored < 1))
         {
             ImageStatus = EIS_InvalidValue;
-            DCMIMGLE_ERROR("invalid values for 'BitsAllocated' (" << BitsAllocated << "), "
-                << "'BitsStored' (" << BitsStored << ") and/or 'HighBit' (" << HighBit << ")");
+            DCMIMGLE_ERROR("invalid value(s) for 'BitsAllocated' (" << BitsAllocated << "), "
+                << "and/or 'BitsStored' (" << BitsStored << ")");
+            return;
+        }
+        else if ((BitsAllocated < BitsStored) || (BitsAllocated <= HighBit) || ((BitsStored - 1) > HighBit))
+        {
+            ImageStatus = EIS_InvalidValue;
+            DCMIMGLE_ERROR("invalid combination of values for 'BitsAllocated' (" << BitsAllocated << "), "
+                << "'BitsStored' (" << BitsStored << ") and 'HighBit' (" << HighBit << ")");
             return;
         }
         else if ((evr == EVR_OB) && (BitsStored <= 8))
@@ -883,7 +889,7 @@ int DiImage::writeBMP(FILE *stream,
                 result = 1;
         }
         /* delete pixel data */
-        delete OFstatic_cast(char *, data);     // type cast necessary to avoid compiler warnings using gcc >2.95
+        delete[] OFstatic_cast(char *, data);
     }
     return result;
 }
index 8c704fe9242749b06a768bc91ea0318049eddc24..2ded9097a8818e96d01e19bde9b7611c08457364 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2021, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcsequen.h"
 #include "dcmtk/dcmdata/dcitem.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
 #include "dcmtk/dcmdata/dcvrus.h"
 
+#include "dcmtk/dcmimgle/dibaslut.h"
+#include "dcmtk/dcmimgle/diutils.h"
 #include "dcmtk/ofstd/ofbmanip.h"
 #include "dcmtk/ofstd/ofcast.h"
 
@@ -90,34 +93,32 @@ DiLookupTable::DiLookupTable(const DcmUnsignedShort &data,
     OriginalBitsAllocated(16),
     OriginalData(NULL)
 {
-    Uint16 us = 0;
-    const DcmElement *descElem = OFreinterpret_cast(const DcmElement *, &descriptor);
-    if (DiDocument::getElemValue(descElem, us, 0, OFTrue /*allowSigned*/) >= 3)         // number of LUT entries
+    const Uint16 *dataPtr = NULL;
+    const unsigned long count = DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &data), dataPtr);
+    Init(dataPtr, count, descriptor, explanation, descripMode, first, status);
+}
+
+
+DiLookupTable::DiLookupTable(const DcmOtherByteOtherWord &data,
+                             const DcmUnsignedShort &descriptor,
+                             const DcmLongString *explanation,
+                             const EL_BitsPerTableEntry descripMode,
+                             const signed long first,
+                             EI_Status *status)
+  : DiBaseLUT(),
+    OriginalBitsAllocated(16),
+    OriginalData(NULL)
+{
+    /* check whether we have OW (16 bit data) since OB (8 bit) is not permitted for LUT data */
+    if (data.getVR() == EVR_OW)
     {
-        Count = (us == 0) ? MAX_TABLE_ENTRY_COUNT : us;                                 // see DICOM supplement 5: "0" => 65536
-        DiDocument::getElemValue(descElem, FirstEntry, 1, OFTrue /*allowSigned*/);      // can be SS or US (will be typecasted later)
-        if ((first >= 0) && (FirstEntry != OFstatic_cast(Uint16, first)))
-        {
-            DCMIMGLE_WARN("invalid value for 'FirstInputValueMapped' in lookup table ("
-                << FirstEntry << ") ... assuming " << first);
-            FirstEntry = OFstatic_cast(Uint16, first);
-        }
-        DiDocument::getElemValue(descElem, us, 2, OFTrue /*allowSigned*/);              // bits per entry (only informational)
-        unsigned long count = DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &data), Data);
-        OriginalData = OFstatic_cast(void *, OFconst_cast(Uint16 *, Data));             // store pointer to original data
-        if (explanation != NULL)
-            DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, explanation), Explanation);   // explanation (free form text)
-        checkTable(count, us, descripMode, status);
-     } else {
-        if (status != NULL)
-        {
-            *status = EIS_MissingAttribute;
-            DCMIMGLE_ERROR("incomplete or missing 'LookupTableDescriptor' " << descriptor.getTag());
-        } else {
-            DCMIMGLE_WARN("incomplete or missing 'LookupTableDescriptor' " << descriptor.getTag()
-                << " ... ignoring LUT");
-        }
-     }
+        const Uint16 *dataPtr = NULL;
+        const unsigned long count = DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, &data), dataPtr);
+        Init(dataPtr, count, descriptor, explanation, descripMode, first, status);
+    } else {
+        DCMIMGLE_ERROR("invalid VR for 'LookupTableData' " << data.getTag());
+        *status = EIS_InvalidImage;
+    }
 }
 
 
@@ -158,7 +159,7 @@ void DiLookupTable::Init(const DiDocument *docu,
         Count = (us == 0) ? MAX_TABLE_ENTRY_COUNT : us;                          // see DICOM supplement 5: "0" => 65536
         docu->getValue(descriptor, FirstEntry, 1, item, OFTrue /*allowSigned*/); // can be SS or US (will be typecasted later)
         docu->getValue(descriptor, us, 2, item, OFTrue /*allowSigned*/);         // bits per entry (only informational)
-        unsigned long count = docu->getValue(data, Data, item);
+        const unsigned long count = docu->getValue(data, Data, item);
         OriginalData = OFstatic_cast(void *, OFconst_cast(Uint16 *, Data));      // store pointer to original data
         if (explanation != DCM_UndefinedTagKey)
             docu->getValue(explanation, Explanation, 0 /*vm pos*/, item);        // explanation (free form text)
@@ -176,6 +177,45 @@ void DiLookupTable::Init(const DiDocument *docu,
 }
 
 
+void DiLookupTable::Init(const Uint16 *data,
+                         const unsigned long count,
+                         const DcmUnsignedShort &descriptor,
+                         const DcmLongString *explanation,
+                         const EL_BitsPerTableEntry descripMode,
+                         const signed long first,
+                         EI_Status *status)
+{
+    Uint16 us = 0;
+    const DcmElement *descElem = OFreinterpret_cast(const DcmElement *, &descriptor);
+    if (DiDocument::getElemValue(descElem, us, 0, OFTrue /*allowSigned*/) >= 3)         // number of LUT entries
+    {
+        Count = (us == 0) ? MAX_TABLE_ENTRY_COUNT : us;                                 // see DICOM supplement 5: "0" => 65536
+        DiDocument::getElemValue(descElem, FirstEntry, 1, OFTrue /*allowSigned*/);      // can be SS or US (will be typecasted later)
+        if ((first >= 0) && (FirstEntry != OFstatic_cast(Uint16, first)))
+        {
+            DCMIMGLE_WARN("invalid value for 'FirstInputValueMapped' in lookup table ("
+                << FirstEntry << ") ... assuming " << first);
+            FirstEntry = OFstatic_cast(Uint16, first);
+        }
+        DiDocument::getElemValue(descElem, us, 2, OFTrue /*allowSigned*/);              // bits per entry (only informational)
+        Data = data;                                                                    // store pointer to passed data
+        OriginalData = OFstatic_cast(void *, OFconst_cast(Uint16 *, Data));             // store pointer to original data
+        if (explanation != NULL)
+            DiDocument::getElemValue(OFreinterpret_cast(const DcmElement *, explanation), Explanation);   // explanation (free form text)
+        checkTable(count, us, descripMode, status);
+    } else {
+        if (status != NULL)
+        {
+            *status = EIS_MissingAttribute;
+            DCMIMGLE_ERROR("incomplete or missing 'LookupTableDescriptor' " << descriptor.getTag());
+        } else {
+            DCMIMGLE_WARN("incomplete or missing 'LookupTableDescriptor' " << descriptor.getTag()
+                << " ... ignoring LUT");
+        }
+    }
+}
+
+
 void DiLookupTable::checkTable(unsigned long count,
                                Uint16 bits,
                                const EL_BitsPerTableEntry descripMode,
@@ -236,8 +276,11 @@ void DiLookupTable::checkTable(unsigned long count,
             for (i = Count; i != 0; --i)
             {
                 value = *(p++);
-                if (((value >> 8) != 0) && (value & 0xff) != (value >> 8))    // lo-byte not equal to hi-byte and ...
-                    cmp = 1;
+                if ((value >> 8) != 0) // if hi-byte is not zero
+                {
+                    if ((value & 0xff) != (value >> 8))    // lo-byte not equal to hi-byte and ...
+                        cmp = 1;
+                }
                 if (value < MinValue)                                         // get global minimum
                     MinValue = value;
                 if (value > MaxValue)                                         // get global maximum
@@ -521,6 +564,18 @@ DiLookupTable *DiLookupTable::createInverseLUT() const
 }
 
 
+int DiLookupTable::compareLUT(const DcmOtherByteOtherWord &data,
+                              const DcmUnsignedShort &descriptor)
+{
+    int result = 1;
+    DiBaseLUT *lut = new DiLookupTable(data, descriptor);
+    if (lut != NULL)
+        result = compare(lut);
+    delete lut;
+    return result;
+}
+
+
 int DiLookupTable::compareLUT(const DcmUnsignedShort &data,
                               const DcmUnsignedShort &descriptor)
 {
index 5a6ba7c767a121a86570afc9ab9731bff638b91b..183722c829e61a211abce7092b38d929fbf37424 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024 OFFIS e.V.
+ *  Copyright (C) 1996-2025 OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -598,7 +598,7 @@ DiMonoImage::~DiMonoImage()
 {
     delete InterData;
     delete OutputData;
-    delete OFstatic_cast(char *, OverlayData);    // type cast necessary to avoid compiler warnings using gcc 2.95
+    delete[] OFstatic_cast(char *, OverlayData);
     if (VoiLutData != NULL)
         VoiLutData->removeReference();            // only delete if object is no longer referenced
     if (PresLutData != NULL)
@@ -950,7 +950,7 @@ const void *DiMonoImage::getOutputPlane(const int) const
 
 void DiMonoImage::deleteOverlayData()
 {
-    delete OFstatic_cast(char *, OverlayData);    // type cast necessary to avoid compiler warnings using gcc 2.95
+    delete[] OFstatic_cast(char *, OverlayData);
     OverlayData = NULL;
 }
 
@@ -1717,18 +1717,19 @@ unsigned long DiMonoImage::createDIB(void *&data,
                         data = new Uint32[count];               // allocated memory buffer
                     if (data != NULL)
                     {
-                        Uint32 *q = OFstatic_cast(Uint32 *, data);
-                        Uint32 value;
+                        Uint8 *q = OFstatic_cast(Uint8 *, data);
+                        Uint8 value;
                         Uint16 x;
                         Uint16 y;
+                        int j;
                         for (y = Rows; y != 0; --y)
                         {
                             for (x = Columns; x != 0; --x)
                             {
                                 value = *(p++);                 // store gray value
-                                *(q++) = (value << 16) |
-                                         (value << 8) |
-                                         value;                 // copy to the three RGB-planes
+                                for (j = 3; j != 0; --j)
+                                    *(q++) = value;             // copy to the three RGB-planes
+                                *(q++) = 0;                     // alpha channel is always zero
                             }
                             p += nextRow;                       // jump (backwards) to next row
                         }
diff --git a/dcmiod/include/dcmtk/dcmiod/iccexample.h b/dcmiod/include/dcmtk/dcmiod/iccexample.h
new file mode 100644 (file)
index 0000000..5875927
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *
+ *  Copyright (C) 2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmiod
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Example ICC profile data for sRGB color space
+ *
+ */
+
+#ifndef ICCEXAMPLE_H
+#define ICCEXAMPLE_H
+
+// The given ICC profile is a small valid ICC profile for sRGB color space that can be used
+// in case no other profile is available. It is based on the example profile given in
+// https://github.com/saucecontrol/Compact-ICC-Profiles (sRGB-v2-magic.icc using 182-Point Curve)
+
+const unsigned char DCMTK_SRGB_ICC_SAMPLE[] = {
+  0x00, 0x00, 0x02, 0xe0, 0x6c, 0x63, 0x6d, 0x73, 0x02, 0x10, 0x00, 0x00,
+  0x73, 0x63, 0x6e, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
+  0x07, 0xe2, 0x00, 0x03, 0x00, 0x14, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x1d,
+  0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
+  0x73, 0x61, 0x77, 0x73, 0x63, 0x74, 0x72, 0x6c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x68, 0x61, 0x6e, 0x64,
+  0x93, 0xb2, 0x34, 0xa9, 0x0e, 0xb0, 0x22, 0x8a, 0x98, 0xfd, 0x9a, 0xaf,
+  0xa3, 0x67, 0x89, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+  0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x5f,
+  0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x0c,
+  0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x14,
+  0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x00, 0x14,
+  0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x14,
+  0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x00, 0x14,
+  0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x01, 0x78,
+  0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x01, 0x78,
+  0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x01, 0x78,
+  0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00,
+  0x43, 0x43, 0x30, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xf3, 0x54, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xc9,
+  0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
+  0x00, 0x00, 0x38, 0xf2, 0x00, 0x00, 0x03, 0x8f, 0x58, 0x59, 0x5a, 0x20,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x96, 0x00, 0x00, 0xb7, 0x89,
+  0x00, 0x00, 0x18, 0xda, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x24, 0xa0, 0x00, 0x00, 0x0f, 0x85, 0x00, 0x00, 0xb6, 0xc4,
+  0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6,
+  0x00, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x54, 0x00, 0x70, 0x00, 0x8c,
+  0x00, 0xa8, 0x00, 0xc4, 0x00, 0xe1, 0x01, 0x00, 0x01, 0x22, 0x01, 0x46,
+  0x01, 0x6d, 0x01, 0x95, 0x01, 0xc1, 0x01, 0xf0, 0x02, 0x20, 0x02, 0x55,
+  0x02, 0x8b, 0x02, 0xc4, 0x03, 0x01, 0x03, 0x3f, 0x03, 0x82, 0x03, 0xc6,
+  0x04, 0x0e, 0x04, 0x59, 0x04, 0xa7, 0x04, 0xf9, 0x05, 0x4c, 0x05, 0xa4,
+  0x05, 0xfe, 0x06, 0x5c, 0x06, 0xbe, 0x07, 0x21, 0x07, 0x8a, 0x07, 0xf4,
+  0x08, 0x63, 0x08, 0xd5, 0x09, 0x49, 0x09, 0xc3, 0x0a, 0x3f, 0x0a, 0xbf,
+  0x0b, 0x42, 0x0b, 0xc9, 0x0c, 0x54, 0x0c, 0xe1, 0x0d, 0x74, 0x0e, 0x09,
+  0x0e, 0xa2, 0x0f, 0x40, 0x0f, 0xe0, 0x10, 0x85, 0x11, 0x2d, 0x11, 0xda,
+  0x12, 0x8a, 0x13, 0x3e, 0x13, 0xf6, 0x14, 0xb2, 0x15, 0x71, 0x16, 0x36,
+  0x16, 0xfd, 0x17, 0xca, 0x18, 0x99, 0x19, 0x6e, 0x1a, 0x46, 0x1b, 0x22,
+  0x1c, 0x03, 0x1c, 0xe7, 0x1d, 0xd0, 0x1e, 0xbd, 0x1f, 0xae, 0x20, 0xa4,
+  0x21, 0x9e, 0x22, 0x9c, 0x23, 0x9f, 0x24, 0xa5, 0x25, 0xb1, 0x26, 0xc0,
+  0x27, 0xd5, 0x28, 0xed, 0x2a, 0x0a, 0x2b, 0x2b, 0x2c, 0x51, 0x2d, 0x7c,
+  0x2e, 0xaa, 0x2f, 0xde, 0x31, 0x16, 0x32, 0x52, 0x33, 0x94, 0x34, 0xd9,
+  0x36, 0x24, 0x37, 0x73, 0x38, 0xc6, 0x3a, 0x20, 0x3b, 0x7c, 0x3c, 0xdf,
+  0x3e, 0x45, 0x3f, 0xb0, 0x41, 0x21, 0x42, 0x96, 0x44, 0x10, 0x45, 0x8f,
+  0x47, 0x12, 0x48, 0x9b, 0x4a, 0x28, 0x4b, 0xbb, 0x4d, 0x51, 0x4e, 0xee,
+  0x50, 0x8f, 0x52, 0x35, 0x53, 0xe0, 0x55, 0x90, 0x57, 0x45, 0x59, 0x00,
+  0x5a, 0xbe, 0x5c, 0x84, 0x5e, 0x4c, 0x60, 0x1b, 0x61, 0xef, 0x63, 0xc7,
+  0x65, 0xa6, 0x67, 0x89, 0x69, 0x71, 0x6b, 0x5f, 0x6d, 0x51, 0x6f, 0x4a,
+  0x71, 0x46, 0x73, 0x4a, 0x75, 0x51, 0x77, 0x5e, 0x79, 0x71, 0x7b, 0x88,
+  0x7d, 0xa6, 0x7f, 0xc8, 0x81, 0xf0, 0x84, 0x1e, 0x86, 0x50, 0x88, 0x89,
+  0x8a, 0xc5, 0x8d, 0x09, 0x8f, 0x51, 0x91, 0x9f, 0x93, 0xf3, 0x96, 0x4b,
+  0x98, 0xab, 0x9b, 0x0e, 0x9d, 0x78, 0x9f, 0xe7, 0xa2, 0x5b, 0xa4, 0xd6,
+  0xa7, 0x56, 0xa9, 0xdb, 0xac, 0x67, 0xae, 0xf7, 0xb1, 0x8f, 0xb4, 0x2a,
+  0xb6, 0xcc, 0xb9, 0x74, 0xbc, 0x21, 0xbe, 0xd5, 0xc1, 0x8d, 0xc4, 0x4c,
+  0xc7, 0x10, 0xc9, 0xda, 0xcc, 0xab, 0xcf, 0x7f, 0xd2, 0x5c, 0xd5, 0x3d,
+  0xd8, 0x24, 0xdb, 0x12, 0xde, 0x04, 0xe0, 0xfe, 0xe3, 0xfc, 0xe7, 0x01,
+  0xea, 0x0c, 0xed, 0x1c, 0xf0, 0x34, 0xf3, 0x50, 0xf6, 0x73, 0xf9, 0x9b,
+  0xfc, 0xca, 0xff, 0xff
+};
+
+unsigned int DCMTK_SRGB_ICC_SAMPLE_LEN = 736;
+
+#endif // ICCEXAMPLE_H
index 744e61fd445294eef9013470d75841b1501f7e8d..464dd08c57a2529abff7dbd7ff46823efbcf0d60 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2021, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -110,6 +110,21 @@ public:
     {
     }
 
+    /** Set whether attribute values should be checked on writing, i.e. if writing
+     *  should fail if attribute values violate their VR, VM, character set or value length.
+     *  A missing but required value is always considered an error, independent of this setting.
+     *  If set to OFFalse, writing will always succeed, even if attribute value constraints
+     *  are violated. A warning instead of an error will be printed to the logger.
+     *  @param  doCheck If OFTrue, attribute value errors are handled as errors on writing, if OFFalse
+     *          any errors are ignored.
+     */
+    virtual void setValueCheckOnWrite(const OFBool doCheck)
+    {
+        m_ImagePixel.setValueCheckOnWrite(doCheck);
+        m_GeneralImage.setValueCheckOnWrite(doCheck);
+        DcmIODCommon::setValueCheckOnWrite(doCheck);
+    }
+
     virtual void setGeneralImageModuleEnabled(const OFBool enabled)
     {
         m_GeneralImageModuleEnabled = enabled;
index 50ff2e6844184fe5e1fb608a51a647e27f793f10..63c53d527d434bfc337182d53a8f95dcf5cade9d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2021, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -107,6 +107,17 @@ public:
      */
     virtual ~IODRules();
 
+    /** Copy constructor, performs deep copy
+     *  @param  other The other rule set to copy from
+     */
+    IODRules(const IODRules& other);
+
+    /** Assignment operator, performs deep copy
+     *  @param  other The other rule set to copy from
+     *  @return Reference to this object
+     */
+    IODRules& operator=(const IODRules& other);
+
 private:
     /// Map that holds all rules, accessible by their tag key
     OFMap<DcmTagKey, IODRule*> m_Rules;
index e66e01ef637f0b45b7279ef4547c8f746c10924a..cad2a8f566945a6a0440a5fb6a7ddad8d3695325 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2019, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -26,6 +26,7 @@
 #include "dcmtk/dcmiod/ioddef.h"
 #include "dcmtk/oflog/oflog.h"
 #include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmdata/dcerror.h"
 
 // ----------------------------------------------------------------------------
 // Define the loggers for this module
@@ -57,6 +58,7 @@ extern DCMTK_DCMIOD_EXPORT const OFConditionConst IOD_EC_InvalidLaterality;
 extern DCMTK_DCMIOD_EXPORT const OFConditionConst IOD_EC_InvalidElementValue;
 extern DCMTK_DCMIOD_EXPORT const OFConditionConst IOD_EC_InvalidReference;
 extern DCMTK_DCMIOD_EXPORT const OFConditionConst IOD_EC_ReferencesOmitted;
+extern DCMTK_DCMIOD_EXPORT const OFConditionConst IOD_EC_InvalidColorPalette;
 
 /** Class that wraps some constant definitions in the context of IODs
  */
@@ -64,19 +66,226 @@ class DCMTK_DCMIOD_EXPORT DcmIODTypes
 {
 
 public:
+    /** Base class to store pixel data for frames. Right now 8 and 16 bit are supported.
+     *  Per default, the class will release memory in the destructor.
+     */
+    struct FrameBase
+    {
+        /// Destructor
+        FrameBase() {}
+        /** Returns pixel data size in bytes
+         *  @return Size of pixel data in bytes
+         */
+        virtual size_t getLengthInBytes() const = 0;
+
+        /** Get pointer to pixel data
+         *  @return Pointer to pixel data
+         */
+        virtual void* getPixelData() const = 0;
+
+        /** Get bytes used per pixel
+         *  @return Bytes per pixel (right now 8 or 16)
+         */
+        virtual Uint8 bytesPerPixel() const = 0;
+
+        /** Get value at given index as 8 bit value
+         *  @param byteVal The value at the given index
+         *  @param index The index to get the value from
+         *  @return EC_Normal if successful, EC_IllegalCall if index is out of bounds
+         */
+        virtual OFCondition getUint8AtIndex(Uint8 &byteVal, const size_t index) const =0;
+
+        /** Get value at given index as 16 bit value
+         *  @param shortVal The value at the given index
+         *  @param index The index to get the value from
+         *  @return EC_Normal if successful, EC_IllegalCall if index is out of bounds
+         */
+        virtual OFCondition getUint16AtIndex(Uint16 &shortVal, const size_t index) const =0;
+
+        /** Set whether Frame class should release memory (default) or whether it will
+         *  be released externally.
+         *  @param release OFTrue if Frame should release memory, OFFalse otherwise
+         */
+        virtual void setReleaseMemory(OFBool release) = 0;
+
+        /** Print frame data to string (for debugging purposes)
+         *  @return String representation of frame data
+         */
+        virtual OFString print() const = 0;
+
+        /** Deconstructor, frees frame data if not disabled via setReleaseMemory() method
+         */
+        virtual ~FrameBase() {}
+    };
+
     /** Struct representing a single frame
      */
-    struct Frame
+    template<typename PixelType>
+    class Frame : public FrameBase
     {
+    public:
+
+        /** Default constructor
+         */
+        Frame() : m_pixData(NULL), m_numPixels(0), m_releaseMemory(OFTrue) {}
+
+        /** Constructor that creates pixel data of the given size (amount of pixels)
+         *  @param numPixels Number of pixels to allocate
+         */
+        Frame(const size_t numPixels) : m_pixData(NULL), m_numPixels(numPixels), m_releaseMemory(OFTrue)
+        {
+            m_pixData = new PixelType[numPixels];
+        }
+
+        /** Constructor that takes over pixel data for managing
+         *  @param pixelData Pointer to pixel data that is afterwards managed by this class
+         *  @param sizeInBytes Size of pixel data in bytes
+         */
+        Frame(PixelType* pixelData, const size_t sizeInBytes) : m_pixData(pixelData), m_numPixels(0), m_releaseMemory(OFTrue)
+        {
+            m_numPixels = sizeInBytes / sizeof(PixelType);
+        }
+
+        /** Copy constructor, copies pixel data
+         *  @param rhs Frame to copy
+         */
+        Frame(const Frame& rhs)
+        {
+            delete[] m_pixData;
+            m_pixData = new PixelType[rhs.m_numPixels];
+            memcpy(m_pixData, rhs.m_pixData, rhs.m_numPixels);
+            m_numPixels = rhs.m_numPixels;
+            m_releaseMemory = rhs.m_releaseMemory;
+        };
+
+        /** Assignment constructor, copies pixel data
+         *  @param rhs Frame to copy from
+         *  @return Reference to this object
+         */
+        Frame& operator=(const Frame& rhs)
+        {
+            if (this != &rhs)
+            {
+                delete[] m_pixData;
+                m_pixData = new PixelType[rhs.m_numPixels];
+                memcpy(m_pixData, rhs.m_pixData, rhs.m_numPixels);
+                m_numPixels = rhs.m_numPixels;
+                m_releaseMemory = rhs.m_releaseMemory;
+            }
+            return *this;
+        }
+
+        /** Set whether pixel data should be release by this class (default)
+         *  or is managed externally.
+         *  @param release OFTrue if memory should be released, OFFalse otherwise
+         */
+        virtual void setReleaseMemory(OFBool release)
+        {
+            m_releaseMemory = release;
+        }
+
+        /** Get size of pixel data in bytes
+         *  @return Size of pixel data in bytes
+         */
+        virtual size_t getLengthInBytes() const
+        {
+            return m_numPixels * bytesPerPixel(); // PixelType is always 1 or 2 bytes
+        }
+
+        /** Returns pointer to pixel data (untyped)
+         *  @return Pointer to pixel data
+         */
+        virtual void* getPixelData() const
+        {
+            return m_pixData;
+        }
+
+        /** Returns pointer to pixel data (typed)
+         *  @return Pointer to pixel data
+         */
+        virtual PixelType* getPixelDataTyped() const
+        {
+            return m_pixData;
+        }
+
+        /** Returns number of pixels (not necessarily bytes) in the frame
+         *  @return Number of pixels
+         */
+        virtual Uint8 bytesPerPixel() const
+        {
+            return sizeof(PixelType);
+        }
+
+        /** Get value at given index as 8 bit value
+         *  @param byteVal The value at the given index
+         *  @param index The index to get the value from
+         *  @return EC_Normal if successful, EC_IllegalCall if index is out of bounds
+         */
+        virtual OFCondition getUint8AtIndex(Uint8 &byteVal, const size_t index) const
+        {
+            if (index >= m_numPixels) {
+                return EC_IllegalCall;
+            }
+            // Since sizeof(PixelType) is known during compile time an
+            // we would require C++11 to mark the condition as constexpr
+            // we disable the related warning in general.
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_VISUAL_STUDIO_CONSTANT_EXPRESSION_WARNING
+// Add range check for 16-bit to 8-bit conversion
+            if (sizeof(PixelType) == 2 && m_pixData[index] > 255) {
+                DCMIOD_ERROR("Value in the frame is too large to be cast to 8 bits");
+                return EC_IllegalCall;
+            }
+            byteVal = static_cast<Uint8>(m_pixData[index]);
+            return EC_Normal;
+        }
+#include DCMTK_DIAGNOSTIC_POP
+
+        /** Get value at given index as 16 bit value
+         *  @param shortVal The value at the given index
+         *  @param index The index to get the value from
+         *  @return EC_Normal if successful, EC_IllegalCall if index is out of bounds
+         */
+        virtual OFCondition getUint16AtIndex(Uint16 &shortVal, const size_t index) const
+        {
+            if (index >= m_numPixels) {
+                return EC_IllegalCall;
+            }
+            shortVal = static_cast<Uint16>(m_pixData[index]);
+            return EC_Normal;
+        }
+
+        /** Print frame data to string (for debugging purposes)
+         *  @return String representation of frame data
+         */
+        virtual OFString print() const
+        {
+            OFStringStream ss;
+            ss << "Frame with " << m_numPixels << " bytes:\n";
+            for (size_t i = 0; i < m_numPixels; i++)
+            {
+                ss << STD_NAMESPACE hex << OFstatic_cast(Uint16, m_pixData[i]) << " ";
+            }
+            ss << "\n";
+            return ss.str().c_str();
+        }
+
         /// Array for the pixel data bytes
-        Uint8* pixData;
-        /// Number of pixel data bytes (i.e.\ Bits Allocated)
-        size_t length;
-        /// Destructor, frees memory
+        PixelType* m_pixData;
+        /// Number of pixels in the frame
+        size_t m_numPixels;
+        // Denote whether to release memory in destructor
+        OFBool m_releaseMemory;
+
+        /** Destructor, frees memory if not disabled via setReleaseMemory() method
+         */
         ~Frame()
         {
-            delete[] pixData;
-            pixData = NULL;
+            if (m_releaseMemory)
+            {
+                delete[] m_pixData;
+                m_pixData = NULL;
+            }
         }
     };
 
@@ -136,4 +345,5 @@ private:
     ~DcmIODTypes() {};
 };
 
+
 #endif // IODTYPES_H
index 499e0cac0652934d9530aceadcc88bfe01fda2fd..01446bd7a217e2ce1f1b4183144468ca4bcb19ad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -106,7 +106,7 @@ public:
      *          (Would be 'const' if the methods from 'dcmdata' would also
      *          be 'const')
      *  @param  delem DICOM element that is set to a copy of the dataset's
-     *          orinal element
+     *          original element
      *  @param  rule  Rule describing parameters to be checked on element.
      *  @return EC_Normal if element could be retrieved and value is correct, an
      *          error code otherwise
@@ -847,6 +847,24 @@ public:
         container.clear();
     }
 
+
+    /** Deletes all elements from given map and calls "delete" on each
+     *  of them to clear memory.
+     *  @param container  The map that should be cleared. Must contain
+     *         pointers to objects that are allocated on the heap.
+     */
+    template <class Map>
+    static void freeMap(Map& container)
+    {
+        typename Map::iterator it = container.begin();
+        while (it != container.end())
+        {
+            delete (*it).second;
+            it++;
+        }
+        container.clear();
+    }
+
     /** Clones and copies all elements from source to destination container by
      *  copy constructing all elements.
      *  If copying fails (because memory is exhausted), EC_MemoryExhausted is returned
@@ -910,6 +928,12 @@ public:
         return 0;
     }
 
+    /** Set the current date and time on the given module by using setContentDate()
+     *  and setContentTime() methods. The current date and time is retrieved
+     *  from the system clock.
+     *  @param  module The module to set the date and time on
+     *  @return EC_Normal if successful, an error code otherwise
+    */
     template <typename ModuleType>
     static OFCondition setContentDateAndTimeNow(ModuleType& module)
     {
@@ -981,7 +1005,7 @@ public:
     static OFCondition extractBinaryFrames(Uint8* pixData,
                                            const size_t numFrames,
                                            const size_t bitsPerFrame,
-                                           OFVector<DcmIODTypes::Frame*>& results);
+                                           OFVector<DcmIODTypes::FrameBase*>& results);
 
     /** Resets the given condition to EC_Normal if checkValue is true and
      *  prints a related message as a warning to the debug logger.
@@ -993,6 +1017,23 @@ public:
      */
     static void resetConditionIfCheckDisabled(OFCondition& result, const OFBool checkValue, DcmElement& elem);
 
+
+    /** If checkValue is true, the given OFCondition for certain errors (listed below), prints
+     *  a debug message if the condition is not good, and resets the condition
+     *  to EC_Normal. If checkValue is false, the method does nothing.
+     *  The following error codes are handled, i.e. reset:
+     *  EC_ValueRepresentationViolated
+     *  EC_MaximumLengthViolated
+     *  EC_InvalidCharacter
+     *  EC_ValueMultiplicityViolated
+     *  @param  result The condition to check. Only EC_ValueRepresentationViolated, EC_MaximumLengthViolated,
+     *          EC_InvalidCharacter and EC_ValueMultiplicityViolated are handled.
+     *  @param checkValue If this value is true, the listed condition are reset to EC_Normal; otherwise the
+     *          condition is not changed and no message is printed.
+     *  @param elem Used if the condition is reset to EC_Normal to print a message in case of a "reset"
+     */
+    static void resetValueCheckResult(OFCondition& result, const OFBool checkValue, DcmElement& elem);
+
 private:
     // We only have static functions so we do not need an instance of
     // this class so far.
index 4346e3e7e6e0c129c0a424794ed1fd9564df34cd..6d02e0e8c488007b5f02ee14c43cb2a0c65fb819 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -83,7 +83,7 @@ public:
      *  An attribute is considered belonging to the module if there are rules
      *  marked as belonging to this module via the rule's module name.
      */
-    void clearData();
+    virtual void clearData();
 
     /** Set missing values by inventing "default values". Automatically
      *  called during write() in IODComponent. In this bas class implementation,
index c5edb1891e9e19920ec20ccd703daa48de900935..149d6ba16edff815183dc2b12bf77c4a87dfd628 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2019, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -168,6 +168,12 @@ public:
      */
     virtual OFCondition getSoftwareVersions(OFString& value, const signed long pos = 0) const;
 
+    /** Get a copy altogether as EquipmentInfo
+     *  @return EquipmentInfo object containing all relevant information
+     *    If some data is not available, it will contain an empty string
+     */
+    virtual IODGeneralEquipmentModule::EquipmentInfo getEquipmentInfo() const;
+
     /** Set Manufacturer
      *  @param  value Value to be set (single value only) or "" for no value
      *  @param  checkValue Check 'value' for conformance with VR (LO) and VM (1)
index 8d4a09a4173838e5015021ed00c62f34951c9541..e533300d24fdbb6a0cedeebdd45eedd47f00cc75 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2019, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -329,7 +329,7 @@ public:
     virtual OFCondition setIrradiationEventUID(const OFString& value, const OFBool checkValue = OFTrue);
 
 private:
-    /// The module's name ("GeneralIamgeModule")
+    /// The module's name ("GeneralImageModule")
     static const OFString m_ModuleName;
 };
 
diff --git a/dcmiod/include/dcmtk/dcmiod/modiccprofile.h b/dcmiod/include/dcmtk/dcmiod/modiccprofile.h
new file mode 100644 (file)
index 0000000..e5052b1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmiod
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Class for managing the ICC Profile Module
+ *
+ */
+
+#ifndef MODICCPROFILE_H
+#define MODICCPROFILE_H
+
+#include "dcmtk/config/osconfig.h"
+
+#include "dcmtk/dcmiod/iodrules.h"
+#include "dcmtk/dcmiod/modbase.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+/** Class representing the ICC Profile Module:
+ *
+ * ICC Profile (0028,2000): (OB, 1, 1)
+ * Color Space (0028,2002): (CS, 3, 1)
+ */
+class DCMTK_DCMIOD_EXPORT IODICCProfileModule : public IODModule
+{
+
+public:
+
+    /** Constructor
+     *  @param  item The item to be used for data storage. If NULL, the
+     *          class creates an empty data container.
+     *  @param  rules The rule set for this class. If NULL, the class creates
+     *          one from scratch and adds its values.
+     */
+    IODICCProfileModule(OFshared_ptr<DcmItem> item, OFshared_ptr<IODRules> rules);
+
+    /** Constructor
+     */
+    IODICCProfileModule();
+
+    /** Destructor
+     */
+    virtual ~IODICCProfileModule();
+
+    /** Clear all attributes from the data that are handled by this module.
+     *  An attribute is considered belonging to the module if there are rules
+     *  marked as belonging to this module via the rule's module name.
+     */
+    virtual void clearData();
+
+    /** Resets rules to their original values
+     */
+    virtual void resetRules();
+
+    /** Get name of module
+     *  @return Name of the module ("ICCProfileModule")
+     */
+    virtual OFString getName() const;
+
+    /** Read attributes from given item into this class
+     *  @param source  The source to read from
+     *  @param clearOldData If OFTrue, old data is cleared before reading. Otherwise
+     *         old data is overwritten (or amended)
+     *  @result EC_Normal if reading was successful, error otherwise
+     */
+    virtual OFCondition read(DcmItem& source, const OFBool clearOldData = OFTrue);
+
+    /** Write attributes from this class into given item
+     *  @param  destination The item to write to
+     *  @result EC_Normal if writing was successful, error otherwise
+     */
+    virtual OFCondition write(DcmItem& destination);
+
+    /** Get the ICC Color Profile data
+     *  @param  value Returns a reference to the icc profile data
+     *  @param  numBytes Number of bytes in the icc profile data returned in value parameter
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getICCProfile(const Uint8*& value, Uint32& numBytes);
+
+    /** Get Color Space
+     *  @param  value Reference to variable in which a copy of the value should be stored
+     *  @param  pos Index of the value to get (0..vm-1), -1 for all components
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getColorSpace(OFString& value, const signed long pos = 0) const;
+
+    /** Set ICC Profile data
+     *  @param  value The value of ICC Profile (will be copied)
+     *  @param  numBytes Number of bytes in the icc profile data (value parameter)
+     *  @param  checkValue Check value for conformance with VR (OB) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition
+    setICCProfile(const Uint8* value, const unsigned long numBytes, const OFBool checkValue = OFTrue);
+
+    /** Set default ICC Profile data (SRGB)
+     *  @param  setColorSpaceDescription If OFTrue, Color Space Description (0028,2004)
+     *          is set to "SRGB" when setting the default profile. If not, this attribute
+     *          is not touched by this method (i.e. by default it remains unset).
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setDefaultProfile(const OFBool& setColorSpaceDescription = OFTrue);
+
+    /** Set Color Space
+     *  @param  value The value of Color Space
+     *  @param  checkValue Check value for conformance with VR (CS) and VM (1) if enabled
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setColorSpace(const OFString& value, const OFBool checkValue = OFTrue);
+
+private:
+
+    /// The module's name ("ICCProfileModule")
+    static const OFString m_ModuleName;
+
+};
+
+#endif // MODICCPROFILE_H
index f06a92eaa883a550baeb1336ebdc72653707de78..4f99e98cafdb2005950640b2405ce282ed45109f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2019, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -257,6 +257,20 @@ public:
             return pBase->read(dataset);
         return IOD_EC_InvalidPixelData;
     }
+
+    /** Set whether attribute values should be checked on writing, i.e. if writing
+     *  should fail if attribute values violate their VR, VM, character set or value length.
+     *  A missing but required value is always considered an error, independent of this setting.
+     *  If set to OFFalse, writing will always succeed, even if attribute value constraints
+     *  are violated. A warning instead of an error will be printed to the logger.
+     *  @param  doCheck If OFTrue, attribute value errors are handled as errors on writing, if OFFalse
+     *          any errors are ignored.
+     */
+    void setValueCheckOnWrite(const OFBool doCheck)
+    {
+      if (IODImagePixelBase* pBase = OFvisit<IODImagePixelBase*>(IODImagePixelVariantBaseVisitor(), *this))
+        pBase->setValueCheckOnWrite(doCheck);
+    }
 };
 
 #endif // MODIMAGEPIXELBASE_H
diff --git a/dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h b/dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h
new file mode 100644 (file)
index 0000000..1956c08
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmiod
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Class for managing the Palette Color Lookup Table Module
+ *
+ */
+
+#ifndef MODPALETTECOLORLUT_H
+#define MODPALETTECOLORLUT_H
+
+#include "dcmtk/config/osconfig.h"
+
+#include "dcmtk/dcmdata/dctagkey.h"
+#include "dcmtk/ofstd/ofmem.h"
+#include "dcmtk/dcmiod/iodrules.h"
+#include "dcmtk/dcmiod/modbase.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+/** Class representing the Palette Color Lookup Table Module:
+ *
+ * Red Palette Color Lookup Table​ Descriptor (0028,1101): (US or SS, 3, 1)
+ * Green Palette Color Lookup Table​ Descriptor (0028,1102): (US or SS, 3, 1)
+ * Blue Palette Color Lookup Table​ Descriptor (0028,1103): (US or SS, 3, 1)
+ * Palette Color Lookup Table UID (0028,1199): (UI, 1, 3)
+ * Red Palette Color Lookup Table​ Data​ (0028,1201): (OW, 1-n, 1C)
+ * Green Palette Color Lookup Table​ Data​ (0028,1202): (OW, 1-n, 1C)
+ * Blue Palette Color Lookup Table​ Data​ (0028,1203): (OW, 1-n, 1C)
+ * Segmented Red Palette Color Lookup Table​ Data​ (0028,1221): (OW, 1-n, 1C)
+ * Segmented Green Palette Color Lookup Table​ Data​ (0028,1222): (OW, 1-n, 1C)
+ * Segmented Blue Palette Color Lookup Table​ Data​ (0028,1223): (OW, 1-n, 1C)
+ */
+class DCMTK_DCMIOD_EXPORT IODPaletteColorLUTModule : public IODModule
+{
+
+public:
+    /** Constructor
+     *  @param  item The item to be used for data storage. If NULL, the
+     *          class creates an empty data container.
+     *  @param  rules The rule set for this class. If NULL, the class creates
+     *          one from scratch and adds its values.
+     */
+    IODPaletteColorLUTModule(OFshared_ptr<DcmItem> item, OFshared_ptr<IODRules> rules);
+
+    /** Constructor
+     */
+    IODPaletteColorLUTModule();
+
+    /** Destructor
+     */
+    virtual ~IODPaletteColorLUTModule();
+
+    /** Clear all attributes from the data that are handled by this module.
+     *  An attribute is considered belonging to the module if there are rules
+     *  marked as belonging to this module via the rule's module name.
+     */
+    virtual void clearData();
+
+    /** Resets rules to their original values
+     */
+    virtual void resetRules();
+
+    /** Get name of module
+     *  @return Name of the module ("PaletteColorLookupTableModule")
+     */
+    virtual OFString getName() const;
+
+    /** Read attributes from given item into this class
+     *  @param source  The source to read from
+     *  @param clearOldData If OFTrue, old data is cleared before reading. Otherwise
+     *         old data is overwritten (or amended)
+     *  @result EC_Normal if reading was successful, error otherwise
+     */
+    virtual OFCondition read(DcmItem& source, const OFBool clearOldData = OFTrue);
+
+    /** Write attributes from this class into given item
+     *  @param  destination The item to write to
+     *  @result EC_Normal if writing was successful, error otherwise
+     */
+    virtual OFCondition write(DcmItem& destination);
+
+    // ---------------- Getters -----------------------------
+
+    /** Returns the number of bits used per LUT data entry.
+     *  If the number of bits is not the same for all LUTs, 0 is returned, indicating an error.
+     *  @return The number of bits used per LUT data entry (8 or 16)
+     */
+    virtual Uint8 numBits();
+
+    /** Get the Red Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Red Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be retrieved (0..2)
+     *  @return EC_Normal if value is found, an error code otherwise
+     */
+    virtual OFCondition getRedPaletteColorLookupTableDescriptor(Uint16& value, const unsigned long pos = 0) const;
+
+    /** Get the Green Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Green Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be retrieved (0..2)
+     *  @return EC_Normal if value is found, an error code otherwise
+     */
+    virtual OFCondition getGreenPaletteColorLookupTableDescriptor(Uint16& value, const unsigned long pos = 0) const;
+
+    /** Get the Blue Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Blue Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be retrieved (0..2)
+     *  @return EC_Normal if value is found, an error code otherwise
+     */
+    virtual OFCondition getBluePaletteColorLookupTableDescriptor(Uint16& value, const unsigned long pos = 0) const;
+
+    /** Get the Palette Color Lookup Table UID
+     *  @param  value Reference to variable in which the value should be stored
+     *  @param  pos Index of the value to get (0..vm-1), -1 for all components
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getPaletteColorLookupTableUID(OFString& value, const signed long pos = 0) const;
+
+    /** Get the Red Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getRedPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Red Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getRedPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Green Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual
+    OFCondition getGreenPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Green Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual
+    OFCondition getGreenPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Blue Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual
+    OFCondition getBluePaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+
+    /** Get the Blue Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual
+    OFCondition getBluePaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+
+    /** Get the Segmented Red Palette Color Lookup Table​ Data​
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedRedPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Segmented Red Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedRedPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Segmented Green Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedGreenPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Segmented Green Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedGreenPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Segmented Blue Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedBluePaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries);
+
+    /** Get the Segmented Blue Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  dataCopy Reference to variable in which a copy of the value should be stored
+     *  @param  numEntries Number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getSegmentedBluePaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries);
+
+    // ---------------- Setters -----------------------------
+
+    /** Set the Red Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Red Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be set (0..2)
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setRedPaletteColorLookupTableDescriptor(const Uint16& value, const unsigned long pos = 0);
+
+    /** Set the Green Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Green Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be set (0..2)
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setGreenPaletteColorLookupTableDescriptor(const Uint16& value, const unsigned long pos = 0);
+
+    /** Set the Blue Palette Color Lookup Table​ Descriptor
+     *  @param  value The value of Blue Palette Color Lookup Table​ Descriptor
+     *  @param  pos The position of the value to be set (0..2)
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setBluePaletteColorLookupTableDescriptor(const Uint16& value, const unsigned long pos = 0);
+
+    /** Set the Palette Color Lookup Table UID
+     *  @param  value The value of Palette Color Lookup Table UID
+     *  @param  checkValue Check value for conformance with VR (UI) and VM (1) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setPaletteColorLookupTableUID(const OFString& value, const OFBool checkValue = OFTrue);
+
+    /** Set the Red Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition
+    setRedPaletteColorLookupTableData(const Uint16* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+    /** Set the Red Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition
+    setRedPaletteColorLookupTableData(const Uint8* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+
+    /** Set the Green Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+
+    virtual OFCondition
+    setGreenPaletteColorLookupTableData(const Uint16* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+    /** Set the Green Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+
+    virtual OFCondition
+    setGreenPaletteColorLookupTableData(const Uint8* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+    /** Set the Blue Palette Color Lookup Table​ Data​ (16 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition
+    setBluePaletteColorLookupTableData(const Uint16* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+    /** Set the Blue Palette Color Lookup Table​ Data​ (8 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition
+    setBluePaletteColorLookupTableData(const Uint8* value, const unsigned long numEntries, const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Red Palette Color Lookup Table​ Data​ (16 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedRedPaletteColorLookupTableData(const Uint16* value,
+                                                           const unsigned long numEntries,
+                                                           const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Red Palette Color Lookup Table​ Data​ (8 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedRedPaletteColorLookupTableData(const Uint8* value,
+                                                           const unsigned long numEntries,
+                                                           const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Green Palette Color Lookup Table​ Data​ (16 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedGreenPaletteColorLookupTableData(const Uint16* value,
+                                                             const unsigned long numEntries,
+                                                             const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Green Palette Color Lookup Table​ Data​ (8 bit version)
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedGreenPaletteColorLookupTableData(const Uint8* value,
+                                                             const unsigned long numEntries,
+                                                             const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Blue Palette Color Lookup Table​ Data​ (16 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedBluePaletteColorLookupTableData(const Uint16* value,
+                                                            const unsigned long numEntries,
+                                                            const OFBool checkValue = OFTrue);
+
+    /** Set the Segmented Blue Palette Color Lookup Table​ Data​ (8 bit version).
+     *  @param  value The value of Red Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in the lookup table
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setSegmentedBluePaletteColorLookupTableData(const Uint8* value,
+                                                            const unsigned long numEntries,
+                                                            const OFBool checkValue = OFTrue);
+
+    // ---------------- Convenience Setters -----------------------------
+
+    /** Set the Palette Color Lookup Table​ Data​ (red, green, blue, 8 or 16 bit).
+     *  @tparam T The data type of the color lookup table data. (Uint16 or Uint8)
+     *  @param  copyRed The value of Red Palette Color Lookup Table​ Data​
+     *  @param  copyGreen The value of Green Palette Color Lookup Table​ Data​
+     *  @param  copyBlue The value of Blue Palette Color Lookup Table​ Data​
+     *  @param  numEntries Number of entries in each of the lookup tables
+     *  @param  checkValue Check value for conformance with VR (OW) and VM (1-n) if OFTrue
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    template <typename T> OFCondition setPaletteColorLookupTableData(const T* copyRed,
+                                               const T* copyGreen,
+                                               const T* copyBlue,
+                                               const unsigned long numEntries,
+                                               const OFBool checkValue = OFTrue);
+
+
+    /** Sets the red, green, and blue data for a segmented palette color lookup table.
+     *  The data arrays for red, green, and blue should be of type T and have a length of numEntries.
+     *  \tparam T The data type of the color lookup table data. (Uint16 or Uint8)
+     *  \param copyRedData Pointer to the array containing the red data.
+     *  \param copyGreenData Pointer to the array containing the green data.
+     *  \param copyBlueData Pointer to the array containing the blue data.
+     *  \param numEntries The number of entries in the lookup table.
+     *  \param checkValue Flag indicating whether to check the input values for validity. Default is true.
+     *  \return EC_Normal if successful, error otherwise.
+     */
+    template <typename T> OFCondition setSegmentedPaletteColorLookupTableData(const T* copyRedData,
+                                                        const T* copyGreenData,
+                                                        const T* copyBlueData,
+                                                        const unsigned long numEntries,
+                                                        const OFBool checkValue = OFTrue);
+
+    /** Sets all three values of the Red Palette Color Lookup Table Descriptor.
+     *  @param numEntries The number of entries in the lookup table.
+     *  @param firstValueMapped The first value mapped in the lookup table.
+     *  @param numBitsPerEntry The number of bits per entry in the lookup table.
+     *
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+     virtual OFCondition setRedPaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                        const Uint16 firstValueMapped,
+                                                        const Uint8 numBitsPerEntry);
+
+    /** Sets all three values of the Green Palette Color Lookup Table Descriptor.
+     *  @param numEntries The number of entries in the lookup table.
+     *  @param firstValueMapped The first value mapped in the lookup table.
+     *  @param numBitsPerEntry The number of bits per entry in the lookup table.
+     *
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setGreenPaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                          const Uint16 firstValueMapped,
+                                                          const Uint8 numBitsPerEntry);
+
+    /** Sets the blue Palette Color Lookup Table Descriptor.
+     *  @param numEntries The number of entries in the lookup table.
+     *  @param firstValueMapped The first value mapped in the lookup table.
+     *  @param numBitsPerEntry The number of bits per entry in the lookup table.
+     *
+     *  @return EC_Normal if value is set, an error code otherwise
+     */
+    virtual OFCondition setBluePaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                         const Uint16 firstValueMapped,
+                                                         const Uint8 numBitsPerEntry);
+
+protected:
+
+    /** Returns a copy of the data for the given tag. A copy of the data is returned into the given
+     *  pointer and the number of entries is returned.
+     *  @param dataTag The tag of the data to be copied (i.e. Red/Green/Blue/PaletteColorLookupTableData)
+     *  @param lutData The pointer that will be set to the copied data
+     *  @param num8BitEntries The number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getUint8DataCopy(const DcmTagKey& dataTag, const Uint8*& lutData, unsigned long& num8BitEntries);
+
+    /** Put the given 8 bit data into the given tag.
+     *  @param dataTag The tag of the data to be copied into (i.e. Red/Green/Blue/PaletteColorLookupTableData)
+     *  @param lutData The data to be copied
+     *  @param num8BitEntries The number of entries in the lookup table
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition putUint8Data(const DcmTagKey& dataTag, const Uint8* lutData, const unsigned long num8BitEntries);
+
+    /** Returns a 16 bit copy of the data for the given tag. The data is returned into the given
+     *  pointer and the number of entries is returned.
+     *  @param dataTag The tag of the data to be copied to (i.e. Red/Green/Blue/PaletteColorLookupTableData)
+     *  @param lutData The pointer that will be set to the copied data
+     *  @param numEntries The number of entries in the data
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getUint16DataCopy(const DcmTagKey& dataTag, const Uint16*& lutData, unsigned long& numEntries);
+
+    /** Returns a reference of the data from the given tag and the number of entries in the data
+     *  @param dataTag The tag of the data to be copied to (i.e. Red/Green/Blue/PaletteColorLookupTableData)
+     *  @param lutData The pointer that will be set to the data
+     *  @param numEntries The number of entries in the data
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getUint16Data(const DcmTagKey& dataTag, const Uint16*& lutData, unsigned long& numEntries);
+
+    /** Check given LUT for consistency with descriptor.
+     *  @param descriptorTag The tag of the descriptor to be checked (i.e. Red/Green/BluePaletteColorLookupTableDescriptor)
+     *  @param dataTag The tag of the data to be checked (i.e. Red/Green/BluePaletteColorLookupTableData).
+     *         Should of course match the descriptor "color".
+     *   @return OFTrue if LUT is consistent, OFFalse otherwise
+     */
+    virtual OFBool checkLUT(const DcmTagKey& descriptorTag,
+                            const DcmTagKey& dataTag);
+
+    /** Check basic consistency rules of all palette descriptors (not their data).
+     *  @param isError If OFTrue, errors are reported, otherwise warnings
+     *  @return OFTrue if all descriptors are consistent, OFFalse otherwise
+     */
+    virtual OFBool checkDescriptorConsistency(const OFBool& isError);
+
+    /** Check basic consistency of all palette data with their descriptors.
+     *  @param isError If OFTrue, errors are reported, otherwise warnings
+     *  @return OFTrue if all data is consistent, OFFalse otherwise
+     */
+    virtual OFBool checkDataConsistency(const OFBool& isError);
+
+    /** Check that either segmented or unsegmented LUT data is used, not both.
+     *  @param isError If OFTrue, errors are reported, otherwise warnings
+     *  @param isSegmented Returns OFTrue if segmented LUT data is used, OFFalse otherwise
+     *  @return OFTrue if LUT data is consistent, OFFalse otherwise
+     */
+    virtual OFBool checkSegmentConsistency(const OFBool& isError, OFBool& isSegmented);
+
+    /** Report error/warning for given descriptor tag.
+     *  @param descriptorTag The tag of the descriptor to be reported (i.e. Red/Green/BluePaletteColorLookupTableDescriptor)
+     *  @param message The message to be reported
+     *  @param isError If OFTrue, an error is reported, otherwise a warning
+     */
+    virtual void reportLUTError(const DcmTagKey& descriptorTag,
+                        const OFString& message,
+                        const OFBool& isError);
+
+    /** Get number of LUT data entries for given descriptor tag.
+     *  @param dataTag The tag of the data to be checked (i.e. Red/Green/BluePaletteColorLookupTableDescriptor)
+     *  @param result The number of entries in the data
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition numEntriesForData(const DcmTagKey& dataTag, Uint16& result);
+
+private:
+
+    /// The module's name ("PaletteColorLookupTableModule")
+    static const OFString m_ModuleName;
+
+};
+
+#endif // MODPALETTECOLORLUT_H
index 02686f543c74055748910483925bcd047b6ee46d..1ea6b95ba941a524f224c0b4229ce831fa02f727 100644 (file)
@@ -21,10 +21,12 @@ DCMTK_ADD_LIBRARY(dcmiod
   modgeneralseries.cc
   modgeneralstudy.cc
   modhelp.cc
+  modiccprofile.cc
   modimagepixel.cc
   modimagepixelbase.cc
   modmultiframefg.cc
   modmultiframedimension.cc
+  modpalettecolorlut.cc
   modpatient.cc
   modpatientstudy.cc
   modsegmentationseries.cc
@@ -33,5 +35,5 @@ DCMTK_ADD_LIBRARY(dcmiod
   modusfor.cc
 )
 
-DCMTK_TARGET_LINK_MODULES(dcmiod dcmdata ofstd oflog)
+DCMTK_TARGET_LINK_MODULES(dcmiod dcmimgle dcmdata ofstd oflog)
 
index 4d4b5eb069e626d78bccd11812b199da5f678aa5..dccf5c7c8f178215b059c0975ceb05b3d9e1b293 100644 (file)
@@ -46,6 +46,8 @@ iodcommn.o: iodcommn.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modcommoninstanceref.h \
@@ -59,7 +61,6 @@ iodcommn.o: iodcommn.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -161,7 +162,9 @@ iodcontentitemmacro.o: iodcontentitemmacro.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -237,7 +240,9 @@ iodmacro.o: iodmacro.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -327,8 +332,9 @@ iodreferences.o: iodreferences.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
- ../include/dcmtk/dcmiod/iodtypes.h ../include/dcmtk/dcmiod/iodutil.h \
- ../include/dcmtk/dcmiod/iodrules.h \
+ ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../include/dcmtk/dcmiod/iodutil.h ../include/dcmtk/dcmiod/iodrules.h \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h
@@ -375,13 +381,14 @@ iodrules.o: iodrules.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
@@ -435,7 +442,8 @@ iodtypes.o: iodtypes.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def
 iodutil.o: iodutil.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmiod/iodutil.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
@@ -501,6 +509,7 @@ iodutil.o: iodutil.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -558,6 +567,8 @@ modacquisitioncontext.o: modacquisitioncontext.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -570,7 +581,6 @@ modacquisitioncontext.o: modacquisitioncontext.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -641,6 +651,7 @@ modbase.o: modbase.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../include/dcmtk/dcmiod/iodutil.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
@@ -713,7 +724,9 @@ modcommoninstanceref.o: modcommoninstanceref.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -776,6 +789,8 @@ modenhequipment.o: modenhequipment.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -788,7 +803,6 @@ modenhequipment.o: modenhequipment.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -871,7 +885,9 @@ modenhusimage.o: modenhusimage.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -954,7 +970,9 @@ modenhusseries.o: modenhusseries.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -1014,6 +1032,8 @@ modequipment.o: modequipment.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1026,7 +1046,6 @@ modequipment.o: modequipment.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -1110,6 +1129,7 @@ modfloatingpointimagepixel.o: modfloatingpointimagepixel.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h
 modfor.o: modfor.cc ../../config/include/dcmtk/config/osconfig.h \
@@ -1174,6 +1194,7 @@ modfor.o: modfor.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
@@ -1231,6 +1252,8 @@ modgeneralimage.o: modgeneralimage.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1243,7 +1266,6 @@ modgeneralimage.o: modgeneralimage.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -1333,6 +1355,7 @@ modgeneralseries.o: modgeneralseries.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1416,7 +1439,9 @@ modgeneralstudy.o: modgeneralstudy.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -1496,6 +1521,83 @@ modhelp.o: modhelp.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h
+modiccprofile.o: modiccprofile.cc \
+ ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../include/dcmtk/dcmiod/modiccprofile.h \
+ ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../include/dcmtk/dcmiod/modbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../include/dcmtk/dcmiod/iodutil.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../include/dcmtk/dcmiod/iccexample.h
 modimagepixel.o: modimagepixel.cc \
  ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmiod/modimagepixel.h \
@@ -1561,6 +1663,7 @@ modimagepixel.o: modimagepixel.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
@@ -1636,6 +1739,7 @@ modimagepixelbase.o: modimagepixelbase.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -1691,6 +1795,8 @@ modmultiframedimension.o: modmultiframedimension.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1703,7 +1809,6 @@ modmultiframedimension.o: modmultiframedimension.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -1771,6 +1876,8 @@ modmultiframefg.o: modmultiframefg.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1783,7 +1890,6 @@ modmultiframefg.o: modmultiframefg.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -1803,6 +1909,88 @@ modmultiframefg.o: modmultiframefg.cc \
  ../include/dcmtk/dcmiod/iodutil.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h
+modpalettecolorlut.o: modpalettecolorlut.cc \
+ ../../config/include/dcmtk/config/osconfig.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../include/dcmtk/dcmiod/iodtypes.h ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../include/dcmtk/dcmiod/modbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../include/dcmtk/dcmiod/iodrules.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../include/dcmtk/dcmiod/iodutil.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
+ ../../dcmimgle/include/dcmtk/dcmimgle/diutils.h \
+ ../../dcmimgle/include/dcmtk/dcmimgle/didefine.h \
+ ../../dcmimgle/include/dcmtk/dcmimgle/diobjcou.h
 modpatient.o: modpatient.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
@@ -1847,6 +2035,8 @@ modpatient.o: modpatient.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1859,7 +2049,6 @@ modpatient.o: modpatient.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -1924,6 +2113,8 @@ modpatientstudy.o: modpatientstudy.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modbase.h \
@@ -1936,7 +2127,6 @@ modpatientstudy.o: modpatientstudy.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -2020,6 +2210,7 @@ modsegmentationseries.o: modsegmentationseries.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../include/dcmtk/dcmiod/iodutil.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
@@ -2094,6 +2285,7 @@ modsopcommon.o: modsopcommon.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
@@ -2181,6 +2373,7 @@ modsynchronization.o: modsynchronization.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -2248,6 +2441,7 @@ modusfor.o: modusfor.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../include/dcmtk/dcmiod/ioddef.h ../include/dcmtk/dcmiod/iodrules.h \
  ../include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
index 14f20c0f3b16946ed61016f52d7f44fc837dbda5..9d0820cc237690c30a6cb76ed84bcace46b89a3c 100644 (file)
@@ -15,8 +15,9 @@ include $(configdir)/@common_makefile@
 ofstddir = $(top_srcdir)/../ofstd
 oflogdir = $(top_srcdir)/../oflog
 dcmdatadir = $(top_srcdir)/../dcmdata
+dcmimgledir = $(top_srcdir)/../dcmimgle
 
-LOCALINCLUDES = -I$(ofstddir)/include -I$(oflogdir)/include -I$(dcmdatadir)/include
+LOCALINCLUDES = -I$(ofstddir)/include -I$(oflogdir)/include -I$(dcmdatadir)/include -I$(dcmimgledir)/include
 
 LOCALDEFS =
 
@@ -26,7 +27,7 @@ objs =  cielabutil.o iodcommn.o  iodcontentitemmacro.o iodmacro.o iodreferences.
        modfloatingpointimagepixel.o modfor.o modgeneralimage.o modgeneralseries.o \
        modgeneralstudy.o modhelp.o  modimagepixelbase.o modimagepixel.o modmultiframedimension.o \
        modmultiframefg.o modpatient.o  modpatientstudy.o modsegmentationseries.o modsopcommon.o \
-       modsynchronization.o modusfor.o
+       modsynchronization.o modusfor.o modiccprofile.o modpalettecolorlut.o
 
 library = libdcmiod.$(LIBEXT)
 
index c0d7f994c4b0a4a5037929025693c19fc685492b..f4c026f4e03b935b03a14851e84e1b38b8859148 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -68,7 +68,9 @@ CodeSequenceMacro::CodeSequenceMacro(const OFString& codeValue,
 {
     // reset element rules
     resetRules();
-    set(codeValue, codingSchemeDesignator, codeMeaning, codingSchemeVersion);
+    // We don't check the value here, since this is a convenience constructor and we
+    // cannot return an error code anyway
+    set(codeValue, codingSchemeDesignator, codeMeaning, codingSchemeVersion, OFFalse /* checkValue */);
 }
 
 OFCondition CodeSequenceMacro::check(const bool /* quiet */)
@@ -96,7 +98,9 @@ CodeSequenceMacro::CodeSequenceMacro(OFshared_ptr<DcmItem> item,
 {
     // reset element rules
     resetRules();
-    set(codeValue, codingSchemeDesignator, codeMeaning, codingSchemeVersion);
+    // We don't check the value here, since this is a convenience constructor and we
+    // cannot return an error code anyway
+    set(codeValue, codingSchemeDesignator, codeMeaning, codingSchemeVersion, OFFalse /* checkValue */);
 }
 
 OFString CodeSequenceMacro::getName() const
@@ -777,7 +781,10 @@ OFCondition ImageSOPInstanceReferenceMacro::create(const OFString& sopClassUID,
     {
         if (!refFramesOrSegments.empty())
         {
-            if (sopClassUID == UID_SegmentationStorage)
+            if ( (sopClassUID == UID_SegmentationStorage)
+                 || (sopClassUID == UID_LabelMapSegmentationStorage)
+                 || (sopClassUID == UID_SurfaceSegmentationStorage)
+                 || (sopClassUID == UID_HeightMapSegmentationStorage) )
             {
                 cond = result->setReferencedSegmentNumber(refFramesOrSegments);
             }
@@ -1271,10 +1278,10 @@ ContentIdentificationMacro::ContentIdentificationMacro(const OFString& instanceN
     , m_IODRules()
 {
     resetRules();
-    setInstanceNumber(instanceNumber);
-    setContentLabel(contentLabel);
-    setContentDescription(contentDescription);
-    setContentCreatorName(contentCreatorName);
+    setInstanceNumber(instanceNumber, OFFalse /* do not check value */);
+    setContentLabel(contentLabel, OFFalse /* do not check value */);
+    setContentDescription(contentDescription, OFFalse /* do not check value */);
+    setContentCreatorName(contentCreatorName, OFFalse /* do not check value */);
 }
 
 void ContentIdentificationMacro::resetRules()
index 80f90c2b8e362b5641603414554853bb4bfe8b67..4689f6c522748082f4cc452a411dcc2a365f3b7f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -37,33 +37,46 @@ IODRules* IODRules::clone()
     IODRules* newRules = new IODRules();
     if (newRules)
     {
-        OFMap<DcmTagKey, IODRule*>::iterator it = m_Rules.begin();
-        while (it != m_Rules.end())
+        *newRules = *this;
+    }
+    else
+    {
+        DCMIOD_WARN("Cannot create new IODRules, memory exhausted?");
+    }
+    return newRules;
+}
+
+// Copy constructor
+IODRules::IODRules(const IODRules& other)
+    : m_Rules()
+{
+   // use assignment operator
+   *this = other;
+}
+
+// Assignment operator (deep copy)
+IODRules& IODRules::operator=(const IODRules& other)
+{
+    if (this != &other)
+    {
+        clear();  // Clear existing rules
+        // Perform deep copy of all rules
+        OFMap<DcmTagKey, IODRule*>::const_iterator it = other.m_Rules.begin();
+        while (it != other.m_Rules.end())
         {
-            if (it->second)
+            IODRule* newRule = it->second->clone();
+            if (newRule)
             {
-                IODRule* newRule = it->second->clone();
-                if (newRule)
-                {
-                    newRules->addRule(newRule);
-                }
-                else
-                {
-                    DCMIOD_WARN("Cannot create new IODRule, memory exhausted?");
-                }
+                m_Rules.insert(OFMake_pair(it->first, newRule));
             }
             else
             {
-                DCMIOD_WARN("Found NULL IODRule, cannot clone");
+                DCMIOD_WARN("Cannot create new IODRule, memory exhausted?");
             }
-            it++;
+            ++it;
         }
     }
-    else
-    {
-        DCMIOD_WARN("Cannot create new IODRules, memory exhausted?");
-    }
-    return newRules;
+    return *this;
 }
 
 IODRule* IODRules::getByTag(const DcmTagKey& key) const
@@ -160,7 +173,7 @@ void IODRules::dump(STD_NAMESPACE ostream& out)
     IODRules::iterator it = m_Rules.begin();
     while (it != m_Rules.end())
     {
-        out << (*it).first << ": Type \"" << (*it).second->getType() << "\", VM \"" << (*it).second->getType() << "\""
+        out << (*it).first << ": Type \"" << (*it).second->getType() << "\", VM \"" << (*it).second->getType() << "\" Component: " << (*it).second->getModule()
             << OFendl;
         it++;
     }
index ab2f8aa3b6bb2d967a135acabc983355b6972eb8..d4616cd0e094acd675142e274d19f3c6f6a37662 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -46,3 +46,4 @@ makeOFConditionConst(IOD_EC_InvalidElementValue, OFM_dcmiod, 11, OF_error, "Valu
 makeOFConditionConst(IOD_EC_InvalidReference, OFM_dcmiod, 12, OF_error, "One or more invalid SOP references");
 makeOFConditionConst(
     IOD_EC_ReferencesOmitted, OFM_dcmiod, 13, OF_error, "One or more SOP references have been omitted");
+makeOFConditionConst(IOD_EC_InvalidColorPalette, OFM_dcmiod, 14, OF_error, "Invalid Color Palette LUT");
index 3b6269d0650e936265be54b280005640a3297a7b..e87221470ad60e43a52fdc62ae10b54f12972f8c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -23,7 +23,7 @@
 #include "dcmtk/dcmiod/iodutil.h"
 #include "dcmtk/dcmdata/dctypes.h" // logger
 #include "dcmtk/dcmiod/iodrules.h"
-
+#include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcdicent.h"
 #include "dcmtk/dcmdata/dcdict.h"
@@ -33,7 +33,6 @@
 #include "dcmtk/dcmdata/dcuid.h"
 #include "dcmtk/dcmdata/dcvrda.h"
 #include "dcmtk/dcmdata/dcvrtm.h"
-#include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/ofstd/ofstring.h"
 
 // --- static helpers ---
@@ -197,7 +196,7 @@ DcmIODUtil::addElementToDataset(OFCondition& result, DcmItem& dataset, DcmElemen
                                                result,
                                                rule->getModule().c_str(),
                                                logLevel);
-                    resetConditionIfCheckDisabled(result, checkValue, *delem);
+                    resetValueCheckResult(result, checkValue, *delem);
                 }
                 if (result.good())
                 {
@@ -691,7 +690,7 @@ Uint32 DcmIODUtil::limitMaxFrames(const size_t numFramesPresent, const OFString&
 OFCondition DcmIODUtil::extractBinaryFrames(Uint8* pixData,
                                             const size_t numFrames,
                                             const size_t bitsPerFrame,
-                                            OFVector<DcmIODTypes::Frame*>& results)
+                                            OFVector<DcmIODTypes::FrameBase*>& results)
 {
     if (pixData == NULL)
     {
@@ -736,15 +735,15 @@ OFCondition DcmIODUtil::extractBinaryFrames(Uint8* pixData,
             return EC_MemoryExhausted;
         }
         memset(frameData, 0, bytesPerFrame); // Initialize to 0
-        DcmIODTypes::Frame* frame = new DcmIODTypes::Frame();
+        DcmIODTypes::Frame<Uint8>* frame = new DcmIODTypes::Frame<Uint8>();
         if (frame == NULL)
         {
             DCMIOD_ERROR("Memory exhausted while extracting frames");
             delete[] frameData;
             return EC_MemoryExhausted;
         }
-        frame->pixData = frameData;
-        frame->length = bytesPerFrame;
+        frame->m_pixData = frameData;
+        frame->m_numPixels = bytesPerFrame;
         results.push_back(frame);
     }
 
@@ -762,7 +761,7 @@ OFCondition DcmIODUtil::extractBinaryFrames(Uint8* pixData,
         Uint8 bit = (pixData[inputByteIndex] >> (8 - bitsLeftInInputByte)) & 0x01;
 
         // Set bit in current frame to to position calculated from bitsLeftInTargetByte
-        results[targetFrameIndex]->pixData[targetByteIndex] |= (bit << (8 - bitsLeftInTargetByte));
+        OFstatic_cast(Uint8*, results[targetFrameIndex]->getPixelData())[targetByteIndex] |= (bit << (8 - bitsLeftInTargetByte));
 
         // Move to next bit
         bitsLeftInInputByte--;
@@ -823,3 +822,33 @@ void DcmIODUtil::resetConditionIfCheckDisabled(OFCondition& result, const OFBool
         }
     }
 }
+
+
+void DcmIODUtil::resetValueCheckResult(OFCondition& result, const OFBool checkValue, DcmElement& elem)
+{
+    if (!checkValue)
+    {
+        if ( (result == EC_ValueRepresentationViolated) ||
+             (result == EC_MaximumLengthViolated) ||
+             (result == EC_InvalidCharacter) ||
+             (result == EC_ValueMultiplicityViolated) )
+        {
+            // print element to string
+            OFOStringStream oss;
+            oss << elem.getTag() << " " << DcmVR(elem.getVR()).getVRName() << " ";
+            oss << DcmTag(elem.getTag()).getTagName() << " ";
+            if (elem.getLength() > 1024)
+            {
+                oss << "(value too long for printing)";
+            }
+            {
+                OFString val;
+                elem.getOFString(val, 0, OFTrue);
+                oss << "[" << val << "]";
+            }
+
+            DCMIOD_DEBUG("Ignoring error (" << result.text() <<") when checking element: " << oss.str().c_str());
+            result = EC_Normal;
+        }
+    }
+}
index ae114af9e1a6157f3ff4d8c0a8b9049f1647da6d..b608b19a1446c46750b17fbbc23f680edb8659e5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -105,6 +105,16 @@ OFCondition IODGeneralEquipmentModule::getSoftwareVersions(OFString& value, cons
     return DcmIODUtil::getStringValueFromItem(DCM_SoftwareVersions, *m_Item, value, pos);
 }
 
+IODGeneralEquipmentModule::EquipmentInfo IODGeneralEquipmentModule::getEquipmentInfo() const
+{
+    EquipmentInfo info;
+    getManufacturer(info.m_Manufacturer);
+    getManufacturerModelName(info.m_ManufacturerModelName);
+    getDeviceSerialNumber(info.m_DeviceSerialNumber);
+    getSoftwareVersions(info.m_SoftwareVersions);
+    return info;
+}
+
 OFCondition IODGeneralEquipmentModule::setDeviceSerialNumber(const OFString& value, const OFBool checkValue)
 {
     OFCondition result = (checkValue) ? DcmLongString::checkStringValue(value, "1") : EC_Normal;
index 7aafb00db75b47731663da053dd50c6a79ee9c58..7d2f00d075d4aa39169ae342b987881f62300610 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -39,7 +39,7 @@ const DcmTagKey DcmModuleHelpers::patientModuleTags[] = { DCM_PatientName,
                                                           DCM_RETIRED_OtherPatientIDs,
                                                           DCM_OtherPatientIDsSequence,
                                                           DCM_OtherPatientNames,
-                                                          DCM_EthnicGroup,
+                                                          DCM_RETIRED_EthnicGroup,
                                                           DCM_PatientComments,
                                                           DCM_PatientSpeciesDescription,
                                                           DCM_PatientSpeciesCodeSequence,
diff --git a/dcmiod/libsrc/modiccprofile.cc b/dcmiod/libsrc/modiccprofile.cc
new file mode 100644 (file)
index 0000000..75907c6
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmiod
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Class for managing the ICC Profile Module
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+
+#include "dcmtk/ofstd/ofcast.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dcerror.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
+#include "dcmtk/dcmdata/dcvrcs.h"
+#include "dcmtk/dcmiod/modiccprofile.h"
+#include "dcmtk/dcmiod/iodutil.h"
+#include "dcmtk/dcmiod/iodrules.h"
+#include "dcmtk/dcmiod/iccexample.h"
+
+const OFString IODICCProfileModule::m_ModuleName = "ICCProfileModule";
+
+IODICCProfileModule::IODICCProfileModule(OFshared_ptr<DcmItem> item, OFshared_ptr<IODRules> rules)
+    : IODModule(item, rules)
+{
+    // reset element rules
+    resetRules();
+}
+
+IODICCProfileModule::IODICCProfileModule()
+    : IODModule()
+{
+    resetRules();
+}
+
+
+IODICCProfileModule::~IODICCProfileModule()
+{
+    // nothing to do
+}
+
+void IODICCProfileModule::resetRules()
+{
+    m_Rules->addRule(new IODRule(DCM_ICCProfile, "1", "1", getName(), DcmIODTypes::IE_IMAGE),OFTrue);
+    m_Rules->addRule(new IODRule(DCM_ColorSpace, "1", "3", getName(), DcmIODTypes::IE_IMAGE),OFTrue);
+}
+
+void IODICCProfileModule::clearData()
+{
+    IODModule::clearData();
+}
+
+OFString IODICCProfileModule::getName() const
+{
+    return m_ModuleName;
+}
+
+OFCondition IODICCProfileModule::read(DcmItem& source, const OFBool clearOldData)
+{
+    if (clearOldData)
+        clearData();
+
+    IODComponent::read(source, OFFalse /* data already cleared */);
+    return EC_Normal;
+}
+
+OFCondition IODICCProfileModule::write(DcmItem& destination)
+{
+    return IODComponent::write(destination);
+}
+
+// --- get() functionality ---
+
+OFCondition IODICCProfileModule::getICCProfile(const Uint8*& value, Uint32& numBytes)
+{
+    DcmElement* elem = NULL;
+    OFCondition result = DcmIODUtil::getAndCheckElementFromDataset(*m_Item, elem, getRules()->getByTag(DCM_ICCProfile));
+    if (result.good())
+    {
+        if (elem->ident() == EVR_OB)
+
+        {
+            Uint8* val = NULL;
+            result = OFstatic_cast(DcmOtherByteOtherWord*, elem)->getUint8Array(val);
+            if (result.good())
+            {
+                // detach value pointer and set numBytes
+                value = val;
+                numBytes = elem->getLength();
+                elem->detachValueField();
+            }
+        }
+        else
+        {
+            result = EC_InvalidVR;
+        }
+    }
+    delete elem; // clean up, we copied the value already
+    return result;
+}
+
+OFCondition IODICCProfileModule::getColorSpace(OFString& value, const signed long pos) const
+{
+    return DcmIODUtil::getStringValueFromItem(DCM_ColorSpace, *m_Item, value, pos);
+}
+
+// --- set() functionality ---
+
+OFCondition IODICCProfileModule::setICCProfile(const Uint8* value, const unsigned long numBytes, const OFBool /* not used */)
+{
+    return m_Item->putAndInsertUint8Array(DCM_ICCProfile, value, numBytes);
+}
+
+OFCondition IODICCProfileModule::setDefaultProfile(const OFBool& setColorSpaceDescription)
+{
+    OFCondition result = setICCProfile(DCMTK_SRGB_ICC_SAMPLE, DCMTK_SRGB_ICC_SAMPLE_LEN, OFFalse /* do not check, we expect this is valid */);
+    if (result.good() && setColorSpaceDescription)
+    {
+        result = setColorSpace("SRGB", OFFalse /* do not check, we expect this is valid */);
+    }
+    return result;
+}
+
+OFCondition IODICCProfileModule::setColorSpace(const OFString& value, const OFBool checkValue)
+{
+    OFCondition result;
+    IODRule* rule = getRules()->getByTag(DCM_ColorSpace);
+    if (rule)
+    {
+        result = (checkValue) ? DcmCodeString::checkStringValue(value, rule->getVM()) : EC_Normal;
+        if (result.good()) result = m_Item->putAndInsertOFStringArray(DCM_ColorSpace, value);
+    }
+    else
+    {
+        result = IOD_EC_NoSuchRule;
+    }
+    return result;
+}
index 28e0f3dacbb15019b1a20cea9e20d51d48d53e21..f65d8f1510b869e6abb63b65d5aa2292cacbc805 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -46,6 +46,7 @@ IODMultiframeDimensionModule::IODMultiframeDimensionModule()
     : IODModule()
     , m_DimensionIndexSequence()
     , m_DimensionOrganizationSequence()
+    , m_CheckOnWrite(OFTrue)
 {
     resetRules();
 }
@@ -200,8 +201,8 @@ OFCondition IODMultiframeDimensionModule::checkDimensions(DcmItem* fgItem)
     DcmSequenceOfItems* perFrame = NULL;
     if (fgItem->findAndGetSequence(DCM_PerFrameFunctionalGroupsSequence, perFrame).bad())
     {
-        DCMIOD_WARN(
-            "Will not check dimension consistency with functional groups (no per-frame functional groups found)");
+        DCMIOD_DEBUG(
+            "Omitting dimension consistency check with functional groups (Per-frame FGs not yet present)");
     }
 
     OFCondition result;
diff --git a/dcmiod/libsrc/modpalettecolorlut.cc b/dcmiod/libsrc/modpalettecolorlut.cc
new file mode 100644 (file)
index 0000000..f963ae1
--- /dev/null
@@ -0,0 +1,985 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmiod
+ *
+ *  Author: Michael Onken
+ *
+ *  Purpose: Class for managing the Palette Color LUT Module
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+
+#include "dcmtk/dcmdata/dcelem.h"
+#include "dcmtk/dcmdata/dcerror.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
+#include "dcmtk/dcmdata/dcvrui.h"
+#include "dcmtk/dcmiod/iodtypes.h"
+#include "dcmtk/dcmiod/modbase.h"
+#include "dcmtk/dcmiod/modpalettecolorlut.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dcvrus.h"
+#include "dcmtk/dcmiod/iodutil.h"
+#include "dcmtk/dcmimgle/diluptab.h"
+#include "dcmtk/ofstd/ofmem.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+const OFString IODPaletteColorLUTModule::m_ModuleName = "PaletteColorLookupTableModule";
+
+IODPaletteColorLUTModule::IODPaletteColorLUTModule(OFshared_ptr<DcmItem> item, OFshared_ptr<IODRules> rules)
+    : IODModule(item, rules)
+{
+    // reset element rules
+    resetRules();
+}
+
+IODPaletteColorLUTModule::IODPaletteColorLUTModule()
+    : IODModule()
+{
+    resetRules();
+}
+
+
+IODPaletteColorLUTModule::~IODPaletteColorLUTModule()
+{
+    // nothing to do
+}
+
+void IODPaletteColorLUTModule::resetRules()
+{
+    m_Rules->addRule(new IODRule(DCM_RedPaletteColorLookupTableDescriptor, "3", "1", getName(), DcmIODTypes::IE_IMAGE),
+                     OFTrue);
+    m_Rules->addRule(
+        new IODRule(DCM_GreenPaletteColorLookupTableDescriptor, "3", "1", getName(), DcmIODTypes::IE_IMAGE), OFTrue);
+    m_Rules->addRule(new IODRule(DCM_BluePaletteColorLookupTableDescriptor, "3", "1", getName(), DcmIODTypes::IE_IMAGE),
+                     OFTrue);
+    m_Rules->addRule(new IODRule(DCM_PaletteColorLookupTableUID, "1", "3", getName(), DcmIODTypes::IE_IMAGE), OFTrue);
+    m_Rules->addRule(new IODRule(DCM_RedPaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE),
+                     OFTrue);
+    m_Rules->addRule(new IODRule(DCM_GreenPaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE),
+                     OFTrue);
+    m_Rules->addRule(new IODRule(DCM_BluePaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE),
+                     OFTrue);
+    m_Rules->addRule(
+        new IODRule(DCM_SegmentedRedPaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE), OFTrue);
+    m_Rules->addRule(
+        new IODRule(DCM_SegmentedGreenPaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE),
+        OFTrue);
+    m_Rules->addRule(
+        new IODRule(DCM_SegmentedBluePaletteColorLookupTableData, "1", "1C", getName(), DcmIODTypes::IE_IMAGE), OFTrue);
+}
+
+void IODPaletteColorLUTModule::clearData()
+{
+    IODModule::clearData();
+}
+
+OFString IODPaletteColorLUTModule::getName() const
+{
+    return m_ModuleName;
+}
+
+OFCondition IODPaletteColorLUTModule::read(DcmItem& source, const OFBool clearOldData)
+{
+    if (clearOldData)
+        clearData();
+
+    IODComponent::read(source, OFFalse /* data already cleared */);
+    OFBool isSegmented;
+    checkSegmentConsistency(OFFalse, isSegmented);
+    if (!isSegmented)
+    {
+        checkLUT(DCM_RedPaletteColorLookupTableDescriptor, DCM_RedPaletteColorLookupTableData);
+        checkLUT(DCM_GreenPaletteColorLookupTableDescriptor, DCM_GreenPaletteColorLookupTableData);
+        checkLUT(DCM_BluePaletteColorLookupTableDescriptor, DCM_BluePaletteColorLookupTableData);
+        checkDescriptorConsistency(OFFalse /* only warn */);
+        checkDataConsistency(OFFalse /* only warn */);
+    }
+    return EC_Normal;
+}
+
+OFCondition IODPaletteColorLUTModule::write(DcmItem& destination)
+{
+    OFBool valid, isSegmented;
+    valid = checkSegmentConsistency(OFFalse, isSegmented);
+    if (valid)
+    {
+        if (!isSegmented)
+        {
+            valid = checkLUT(DCM_RedPaletteColorLookupTableDescriptor, DCM_RedPaletteColorLookupTableData);
+            if (valid)
+                valid = checkLUT(DCM_GreenPaletteColorLookupTableDescriptor, DCM_GreenPaletteColorLookupTableData);
+            if (valid)
+                valid = checkLUT(DCM_BluePaletteColorLookupTableDescriptor, DCM_BluePaletteColorLookupTableData);
+            if (valid)
+                valid = checkDescriptorConsistency(OFTrue /* report as errors */);
+            if (valid)
+                valid = checkDataConsistency(OFTrue /* report as errors */);
+            if (valid)
+            {
+                return IODComponent::write(destination);
+            }
+            else
+            {
+                return IOD_EC_InvalidColorPalette;
+            }
+        }
+        else
+        {
+            return IODComponent::write(destination);
+        }
+    }
+
+    return IOD_EC_InvalidColorPalette;
+}
+
+OFCondition IODPaletteColorLUTModule::getRedPaletteColorLookupTableDescriptor(Uint16& value,
+                                                                              const unsigned long pos) const
+{
+    OFCondition result = m_Item->findAndGetUint16(DCM_RedPaletteColorLookupTableDescriptor, value, pos);
+    return result;
+}
+
+OFCondition IODPaletteColorLUTModule::getGreenPaletteColorLookupTableDescriptor(Uint16& value,
+                                                                              const unsigned long pos) const
+{
+    OFCondition result = m_Item->findAndGetUint16(DCM_GreenPaletteColorLookupTableDescriptor, value, pos);
+    return result;
+}
+
+OFCondition IODPaletteColorLUTModule::getBluePaletteColorLookupTableDescriptor(Uint16& value,
+                                                                              const unsigned long pos) const
+{
+    OFCondition result = m_Item->findAndGetUint16(DCM_BluePaletteColorLookupTableDescriptor, value, pos);
+    return result;
+}
+
+
+OFCondition IODPaletteColorLUTModule::getPaletteColorLookupTableUID(OFString& value, const signed long pos) const
+{
+    return DcmIODUtil::getStringValueFromItem(DCM_PaletteColorLookupTableUID, *m_Item, value, pos);
+}
+
+OFCondition IODPaletteColorLUTModule::getRedPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_RedPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getGreenPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_GreenPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getBluePaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_BluePaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedRedPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_SegmentedRedPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedGreenPaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_SegmentedGreenPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedBluePaletteColorLookupTableData(const Uint16*& dataCopy, unsigned long& numEntries)
+{
+    return getUint16DataCopy(DCM_SegmentedBluePaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+// 8 bit versions for LUT data access
+
+OFCondition IODPaletteColorLUTModule::getRedPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_RedPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getGreenPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_GreenPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getBluePaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_BluePaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedRedPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_SegmentedRedPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedGreenPaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_SegmentedGreenPaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+OFCondition IODPaletteColorLUTModule::getSegmentedBluePaletteColorLookupTableData(const Uint8*& dataCopy, unsigned long& numEntries)
+{
+    return getUint8DataCopy(DCM_SegmentedBluePaletteColorLookupTableData, dataCopy, numEntries);
+}
+
+// -------------------- set() --------------------
+
+OFCondition IODPaletteColorLUTModule::setRedPaletteColorLookupTableDescriptor(const Uint16& value,
+                                                                              const unsigned long pos)
+{
+    OFCondition result = m_Item->putAndInsertUint16(DCM_RedPaletteColorLookupTableDescriptor, value, pos);
+    return result;
+}
+
+
+OFCondition IODPaletteColorLUTModule::setGreenPaletteColorLookupTableDescriptor(const Uint16& value,
+                                                                                const unsigned long pos)
+{
+    return m_Item->putAndInsertUint16(DCM_GreenPaletteColorLookupTableDescriptor, value, pos);
+}
+
+
+OFCondition IODPaletteColorLUTModule::setBluePaletteColorLookupTableDescriptor(const Uint16& value,
+                                                                               const unsigned long pos)
+{
+    return m_Item->putAndInsertUint16(DCM_BluePaletteColorLookupTableDescriptor, value, pos);
+}
+
+
+OFCondition IODPaletteColorLUTModule::setPaletteColorLookupTableUID(const OFString& value, const OFBool checkValue)
+{
+    OFCondition result = (checkValue) ? DcmUniqueIdentifier::checkStringValue(value, "1") : EC_Normal;
+    if (result.good()) result = m_Item->putAndInsertOFStringArray(DCM_PaletteColorLookupTableUID, value);
+    return result;
+}
+
+OFCondition IODPaletteColorLUTModule::setRedPaletteColorLookupTableData(const Uint16* data,
+                                                                        const unsigned long numEntries,
+                                                                        const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long fixZero = numEntries;
+    if (numEntries == 0)
+    {
+        fixZero = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_RedPaletteColorLookupTableData, data, fixZero);
+}
+
+OFCondition IODPaletteColorLUTModule::setGreenPaletteColorLookupTableData(const Uint16* data,
+                                                                          const unsigned long numEntries,
+                                                                          const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long fixZero = numEntries;
+    if (numEntries == 0)
+    {
+        fixZero = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_GreenPaletteColorLookupTableData, data, fixZero);
+}
+
+OFCondition IODPaletteColorLUTModule::setBluePaletteColorLookupTableData(const Uint16* data,
+                                                                         const unsigned long numEntries,
+                                                                         const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_BluePaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setRedPaletteColorLookupTableData(const Uint8* data,
+                                                                        const unsigned long numEntries,
+                                                                        const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_RedPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setGreenPaletteColorLookupTableData(const Uint8* data,
+                                                                          const unsigned long numEntries,
+                                                                          const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_GreenPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setBluePaletteColorLookupTableData(const Uint8* data,
+                                                                         const unsigned long numEntries,
+                                                                         const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_BluePaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedRedPaletteColorLookupTableData(const Uint16* data,
+                                                                                 const unsigned long numEntries,
+                                                                                 const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_SegmentedRedPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedGreenPaletteColorLookupTableData(const Uint16* data,
+                                                                                   const unsigned long numEntries,
+                                                                                   const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_SegmentedGreenPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedBluePaletteColorLookupTableData(const Uint16* data,
+                                                                                  const unsigned long numEntries,
+                                                                                  const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 8))
+    {
+        DCMIOD_ERROR("Cannot set 16 bit data for 8 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 65536;
+    }
+    return m_Item->putAndInsertUint16Array(DCM_SegmentedBluePaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedRedPaletteColorLookupTableData(const Uint8* data,
+                                                                                 const unsigned long numEntries,
+                                                                                 const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_SegmentedRedPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedGreenPaletteColorLookupTableData(const Uint8* data,
+                                                                                   const unsigned long numEntries,
+                                                                                   const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_SegmentedGreenPaletteColorLookupTableData, data, zeroFix);
+}
+
+OFCondition IODPaletteColorLUTModule::setSegmentedBluePaletteColorLookupTableData(const Uint8* data,
+                                                                                  const unsigned long numEntries,
+                                                                                  const OFBool checkValue)
+{
+    if (checkValue && (numBits() == 16))
+    {
+        DCMIOD_ERROR("Cannot set 8 bit data for 16 bit LUT");
+        return IOD_EC_InvalidColorPalette;
+    }
+    unsigned long zeroFix = numEntries;
+    if (numEntries == 0)
+    {
+        zeroFix = 256;
+    }
+    return putUint8Data(DCM_SegmentedBluePaletteColorLookupTableData, data, zeroFix);
+}
+
+
+template<typename T>
+OFCondition IODPaletteColorLUTModule::setPaletteColorLookupTableData(const T* redData,
+                                                                     const T* greenData,
+                                                                     const T* blueData,
+                                                                     const unsigned long numEntries,
+                                                                     const OFBool checkValue)
+{
+    OFCondition result = setRedPaletteColorLookupTableData(redData, numEntries, checkValue);
+    if (result.good()) result = setGreenPaletteColorLookupTableData(greenData, numEntries, checkValue);
+    if (result.good()) result = setBluePaletteColorLookupTableData(blueData, numEntries, checkValue);
+    return result;
+}
+
+template<typename T>
+OFCondition IODPaletteColorLUTModule::setSegmentedPaletteColorLookupTableData(const T* redData,
+                                                                              const T* greenData,
+                                                                              const T* blueData,
+                                                                              const unsigned long numEntries,
+                                                                              const OFBool checkValue)
+{
+    OFCondition result = setSegmentedRedPaletteColorLookupTableData(redData, numEntries, checkValue);
+    if (result.good()) result = setSegmentedGreenPaletteColorLookupTableData(greenData, numEntries, checkValue);
+    if (result.good()) result = setSegmentedBluePaletteColorLookupTableData(blueData, numEntries, checkValue);
+    return result;
+}
+
+OFCondition IODPaletteColorLUTModule::setRedPaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                                              const Uint16 firstMapped,
+                                                                              const Uint8 bitsPerEntry)
+{
+    // TODO Check value
+    OFCondition result;
+    Uint16 values[3];
+    values[0] = numEntries;
+    values[1] = firstMapped;
+    values[2] = bitsPerEntry;
+
+    return m_Item->putAndInsertUint16Array(DCM_RedPaletteColorLookupTableDescriptor, values, 3);
+}
+
+
+OFCondition IODPaletteColorLUTModule::setGreenPaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                                                const Uint16 firstMapped,
+                                                                                const Uint8 bitsPerEntry)
+{
+    // TODO check value
+    OFCondition result;
+    Uint16 values[3];
+    values[0] = numEntries;
+    values[1] = firstMapped;
+    values[2] = bitsPerEntry;
+    return m_Item->putAndInsertUint16Array(DCM_GreenPaletteColorLookupTableDescriptor, values, 3);
+}
+
+
+
+OFCondition IODPaletteColorLUTModule::setBluePaletteColorLookupTableDescriptor(const Uint16 numEntries,
+                                                                               const Uint16 firstMapped,
+                                                                               const Uint8 bitsPerEntry)
+{
+    OFCondition result;
+    Uint16 values[3];
+    values[0] = numEntries;
+    values[1] = firstMapped;
+    values[2] = bitsPerEntry;
+
+    return m_Item->putAndInsertUint16Array(DCM_BluePaletteColorLookupTableDescriptor, values, 3);
+}
+
+
+OFBool IODPaletteColorLUTModule::checkLUT(const DcmTagKey& descriptorTag,
+                                          const DcmTagKey& dataTag)
+{
+    DcmElement* data = NULL;
+    DcmElement* descriptor = NULL;
+    m_Item->findAndGetElement(dataTag, data);
+    m_Item->findAndGetElement(descriptorTag, descriptor);
+    if (!data || !descriptor)
+    {
+        reportLUTError(descriptorTag, "Palette Color LUT Data or Descriptor missing", OFFalse /* warning */);
+        return OFFalse;
+    }
+    // LUT Data always OW in this module, LUT Descriptor is always US or SS
+    if ( (data->getTag().getEVR() != EVR_OW) || ( (descriptor->getTag().getEVR() != EVR_US) && (descriptor->getTag().getEVR() != EVR_SS)) )
+    {
+        reportLUTError(descriptorTag, "Palette Color LUT Data or Descriptor have invalid VR", OFFalse /* warning */);
+        return OFFalse;
+    }
+    DiLookupTable lut(*OFstatic_cast(DcmOtherByteOtherWord*, data), *OFstatic_cast(DcmUnsignedShort*, descriptor), NULL, ELM_CheckValue);
+    if (!lut.isValid())
+    {
+        reportLUTError(descriptorTag, "Palette Color LUT Data is invalid", OFFalse /* warning */);
+        return OFFalse;
+    }
+    return OFTrue;
+}
+
+
+void IODPaletteColorLUTModule::reportLUTError(const DcmTagKey& tag, const OFString& message, const OFBool& warning)
+{
+    OFString color;
+    if (tag == DCM_RedPaletteColorLookupTableDescriptor)
+        color = "Red";
+    else if (tag == DCM_GreenPaletteColorLookupTableDescriptor)
+        color = "Green";
+    else if (tag == DCM_BluePaletteColorLookupTableDescriptor)
+        color = "Blue";
+    if (warning)
+        DCMIOD_WARN(color << " " << message);
+    else
+        DCMIOD_ERROR(color << " " << message);
+}
+
+Uint8 IODPaletteColorLUTModule::numBits()
+{
+    OFCondition result;
+    Uint16 numBitsR = 0;
+    Uint16 numBitsG = 0;
+    Uint16 numBitsB = 0;
+    if (getRedPaletteColorLookupTableDescriptor(numBitsR, 2).good() && getGreenPaletteColorLookupTableDescriptor(numBitsG, 2).good() && getBluePaletteColorLookupTableDescriptor(numBitsB, 2).good())
+    {
+        if ((numBitsR != numBitsG) || (numBitsR != numBitsB) || (numBitsG != numBitsB))
+        {
+            DCMIOD_WARN("Bits per entry in Red, Green and Blue Palette Color LUT Descriptor are not equal");
+            return 0;
+        }
+    }
+    else
+    {
+        DCMIOD_WARN("Could not read bits per entry in Red, Green or Blue Palette Color LUT Descriptor");
+        return 0;
+    }
+    if ((numBitsR != 8) && (numBitsR != 16))
+    {
+        DCMIOD_WARN("Bits per entry in Red, Green and Blue Palette Color LUT Descriptor are greater than 16");
+        return 0;
+    }
+    return OFstatic_cast(Uint8, numBitsR);
+}
+
+
+OFBool IODPaletteColorLUTModule::checkDescriptorConsistency(const OFBool& isError)
+{
+    // Check whether all 2nd values ("first value mapped") have same value.
+    Uint16 redFirstMapped = 0;
+    Uint16 greenFirstMapped = 0;
+    Uint16 blueFirstMapped = 0;
+    Sint32 r,g,b;
+    r=g=b=0;
+    if (getRedPaletteColorLookupTableDescriptor(redFirstMapped, 1).good())
+    {
+        if (getGreenPaletteColorLookupTableDescriptor(greenFirstMapped, 1).good())
+        {
+            if (getBluePaletteColorLookupTableDescriptor(blueFirstMapped, 1).good())
+            {
+                r = redFirstMapped;
+                g = greenFirstMapped;
+                b = blueFirstMapped;
+                if ( (r != g) || (r != b) || (g != b) )
+                {
+                    if (isError)
+                    {
+                        DCMIOD_ERROR("First value mapped in Red, Green and Blue Palette Color LUT Descriptor are not equal");
+                    }
+                    else
+                    {
+                        DCMIOD_WARN("First value mapped in Red, Green and Blue Palette Color LUT Descriptor are not equal");
+                    }
+                    return OFFalse;
+                }
+                Uint16 lastRed, lastGreen, lastBlue;
+                lastRed = lastGreen = lastBlue = 0;
+                if (getRedPaletteColorLookupTableDescriptor(lastRed, 2).good() && getGreenPaletteColorLookupTableDescriptor(lastGreen, 2).good() && getBluePaletteColorLookupTableDescriptor(lastBlue, 2).good())
+                {
+                    if (lastRed != lastGreen || lastRed != lastBlue || lastGreen != lastBlue)
+                    {
+                        if (isError)
+                        {
+                            DCMIOD_ERROR("Bits per entry in Red, Green and Blue Palette Color LUT Descriptor are not equal");
+                        }
+                        else
+                        {
+                            DCMIOD_WARN("Bits per entry in Red, Green and Blue Palette Color LUT Descriptor are not equal");
+                        }
+                        return OFFalse;
+                    }
+                    return OFTrue;
+                }
+            }
+        }
+    }
+    if (isError)
+    {
+        DCMIOD_ERROR("Could not read first value mapped in Red, Green or Blue Palette Color LUT Descriptor");
+    }
+    else
+    {
+        DCMIOD_WARN("Could not read first value mapped in Red, Green or Blue Palette Color LUT Descriptor");
+    }
+    return OFFalse;
+}
+
+
+OFBool IODPaletteColorLUTModule::checkDataConsistency(const OFBool& isError)
+{
+    // Check whether all 2nd values ("first value mapped") have same value.
+    Uint16 redFirstMapped, greenFirstMapped, blueFirstMapped, redNumEntries, greenNumEntries, blueNumEntries;
+    unsigned long redActualNumEntries, greenActualNumEntries, blueActualNumEntries;
+    redFirstMapped = greenFirstMapped = blueFirstMapped = redNumEntries = greenNumEntries = blueNumEntries = 0;
+    redActualNumEntries = greenActualNumEntries = blueActualNumEntries = 0;
+    const Uint8 bits = numBits();
+    OFCondition result;
+    OFString message;
+    result = getRedPaletteColorLookupTableDescriptor(redFirstMapped, 1);
+    if (result.good())
+    {
+        result = getGreenPaletteColorLookupTableDescriptor(greenFirstMapped, 1);
+    }
+    if (result.good())
+    {
+        result = getBluePaletteColorLookupTableDescriptor(blueFirstMapped, 1);
+    }
+    if (result.bad())
+    {
+        message = "Could not read first value mapped in Red, Green or Blue Palette Color LUT Descriptor";
+    }
+
+    if (result.good())
+    {
+        if (getRedPaletteColorLookupTableDescriptor(redNumEntries, 0).good())
+        {
+            if (getGreenPaletteColorLookupTableDescriptor(greenNumEntries, 0).good())
+            {
+                if (getBluePaletteColorLookupTableDescriptor(blueNumEntries, 0).good())
+                {
+                    unsigned long maxEntries = 0;
+                    if (bits == 8)
+                    {
+                        maxEntries = 256;
+                        const Uint8* data = NULL;
+                        result = getRedPaletteColorLookupTableData(data, redActualNumEntries);
+                        delete[] data;
+                        if (result.good())
+                        {
+                            result = getGreenPaletteColorLookupTableData(data, greenActualNumEntries);
+                            delete[] data;
+                        }
+                        if (result.good())
+                        {
+                            result = getBluePaletteColorLookupTableData(data, blueActualNumEntries);
+                            delete[] data;
+                        }
+                    }
+                    else if (bits == 16)
+                    {
+                        maxEntries = 65536;
+                        const Uint16* data = NULL;
+                        result = getRedPaletteColorLookupTableData(data, redActualNumEntries);
+                        delete[] data;
+                        if (result.good())
+                        {
+                            result = getGreenPaletteColorLookupTableData(data, greenActualNumEntries);
+                            delete[] data;
+                        }
+                        if (result.good())
+                        {
+                            result = getBluePaletteColorLookupTableData(data, blueActualNumEntries);
+                            delete[] data;
+                        }
+                    }
+                    if (result.good())
+                    {
+                        if ( (redNumEntries != redActualNumEntries) || (greenNumEntries != greenActualNumEntries) || (blueNumEntries != blueActualNumEntries) )
+                        {
+                            // also check special case where number descriptor entries is 0 (i.e. max value)
+                            if ( (!redNumEntries && (redActualNumEntries != maxEntries)) || (!greenNumEntries && (greenActualNumEntries != maxEntries)) || (!blueNumEntries && (blueActualNumEntries != maxEntries)) )
+                            {
+                               message = "Number of entries in Red, Green and Blue Palette Color LUT Data does not match descriptor";
+                            }
+                        }
+                        return OFTrue;
+                    }
+                }
+            }
+        }
+    }
+    if (isError)
+    {
+        DCMIOD_ERROR(message);
+    }
+    else
+    {
+        DCMIOD_WARN(message);
+    }
+    return OFFalse;
+}
+
+
+OFBool IODPaletteColorLUTModule::checkSegmentConsistency(const OFBool& isError, OFBool& isSegmented)
+{
+    // Check that unsegmented LUTs are used together with segmented LUTs
+    isSegmented = OFFalse;
+    OFBool hasNonSegmentedLUTs = OFFalse;
+    OFString msg;
+    // Check for segmented LUT descriptors
+    if (m_Item->tagExists(DCM_SegmentedRedPaletteColorLookupTableData) && m_Item->tagExists(DCM_SegmentedGreenPaletteColorLookupTableData) && m_Item->tagExists(DCM_SegmentedBluePaletteColorLookupTableData))
+    {
+        // Also check for segmented LUT data
+        if (m_Item->tagExists(DCM_SegmentedRedPaletteColorLookupTableData) && m_Item->tagExists(DCM_SegmentedGreenPaletteColorLookupTableData) && m_Item->tagExists(DCM_SegmentedBluePaletteColorLookupTableData))
+        {
+            isSegmented = OFTrue;
+        }
+    }
+    // Check for unsegmented LUT descriptors
+    if (m_Item->tagExists(DCM_RedPaletteColorLookupTableDescriptor) || m_Item->tagExists(DCM_GreenPaletteColorLookupTableDescriptor) || m_Item->tagExists(DCM_BluePaletteColorLookupTableDescriptor))
+    {
+        // Check for unsegmented LUT data
+        if (m_Item->tagExists(DCM_RedPaletteColorLookupTableData) || m_Item->tagExists(DCM_GreenPaletteColorLookupTableData) || m_Item->tagExists(DCM_BluePaletteColorLookupTableData))
+        {
+            hasNonSegmentedLUTs = OFTrue;
+        }
+    }
+    // Check that both are not used together
+    if (isSegmented && hasNonSegmentedLUTs)
+    {
+        msg = "Segmented Palette LUT attributes are used together with Unsegmented LUT attributes";
+    }
+    if (!isSegmented && !hasNonSegmentedLUTs)
+    {
+        msg = "No or incomplete Palette LUT attributes found";
+    }
+    if (msg.length() > 0)
+    {
+        if (isError)
+        {
+            DCMIOD_ERROR(msg);
+        }
+        else
+        {
+            DCMIOD_WARN(msg);
+        }
+        return OFFalse;
+    }
+    return OFTrue;
+}
+
+
+OFCondition IODPaletteColorLUTModule::getUint8DataCopy(const DcmTagKey& dataTag, const Uint8*& lutData, unsigned long& num8BitEntries)
+{
+    OFCondition result = EC_Normal;
+    num8BitEntries = 0;
+
+    const Uint16* data = NULL;
+    unsigned long num16BitEntries = 0;
+    // check first whether we actually have 8 bit data by checking third descriptor value
+    if (numBits() != 8)
+    {
+        DCMIOD_ERROR("Cannot convert 16 bit data to 8 bit data: Descriptor does not indicate 8 bit data");
+        return EC_IllegalParameter;
+    }
+    result = m_Item->findAndGetUint16Array(dataTag, data, &num16BitEntries);
+    if (result.good())
+    {
+        Uint16 numDescriptor = 0;
+        // get number of entries according to first value of descriptor
+        result = numEntriesForData(dataTag, numDescriptor);
+        if (result.bad())
+        {
+            DCMIOD_ERROR("Could not determine number of 8 bit entries for " << dataTag);
+            return IOD_EC_InvalidColorPalette;
+        }
+        num8BitEntries = numDescriptor;
+        if (num8BitEntries == 0)
+        {
+            num8BitEntries = 256;
+        }
+        // check whether number of entries is consistent with number of 16 bit entries
+        if ( (num8BitEntries != num16BitEntries*2) && (num8BitEntries != num16BitEntries*2 -1) )
+        {
+            DCMIOD_DEBUG("Number of 8 bit entries from descriptor: " << numDescriptor << ", Number of 16 bit entries in data: " << num16BitEntries);
+            DCMIOD_ERROR("Number of 8 bit entries does not match number of 16 bit entries");
+            return IOD_EC_InvalidColorPalette;
+        }
+        Uint8* newData = new Uint8[num8BitEntries];
+        if (num8BitEntries > 1)
+        {
+            for (unsigned long i = 0; i < num16BitEntries - 1; i++)
+            {
+                // extract lower and higher byte of 16 bit entry
+                newData[i * 2] = OFstatic_cast(Uint8, data[i] >> 8);
+                newData[i * 2 + 1] = OFstatic_cast(Uint8, data[i] & 0x00FF);
+            }
+        }
+        if (num8BitEntries % 2)
+        {
+            // if odd number of 16 bit entries, only extract lower byte of last entry
+            newData[num8BitEntries-1] = OFstatic_cast(Uint8, data[num16BitEntries-1] >> 8);
+        }
+        else
+        {
+            newData[num8BitEntries-2] = OFstatic_cast(Uint8, data[num16BitEntries-1] >> 8);
+            newData[num8BitEntries-1] = OFstatic_cast(Uint8, data[num16BitEntries-1] & 0x00FF);
+        }
+        lutData = newData;
+    }
+    return result;
+}
+
+
+OFCondition IODPaletteColorLUTModule::getUint16Data(const DcmTagKey& dataTag, const Uint16*& lutData, unsigned long& numEntries)
+{
+    OFCondition result;
+    const Uint16* data = NULL;
+
+    result = m_Item->findAndGetUint16Array(dataTag, data, &numEntries, OFFalse);
+    if (result.good())
+    {
+        lutData = data;
+    }
+    return result;
+}
+
+OFCondition IODPaletteColorLUTModule::getUint16DataCopy(const DcmTagKey& dataTag, const Uint16*& lutData, unsigned long& numEntries)
+{
+    const Uint16* buffer;
+    OFCondition result = getUint16Data(dataTag, buffer, numEntries);
+    if (result.good())
+    {
+        Uint16* newData = new Uint16[numEntries];
+        // copy data
+        for (unsigned long i = 0; i < numEntries; i++)
+        {
+            newData[i] = buffer[i];
+        }
+        lutData = newData;
+    }
+    return result;
+}
+
+
+OFCondition IODPaletteColorLUTModule::putUint8Data(const DcmTagKey& dataTag, const Uint8* lutData, const unsigned long num8BitEntries)
+{
+    if (numBits() != 8)
+    {
+        DCMIOD_ERROR("Cannot convert 8 bit data to 16 bit data: Descriptor does not indicate 8 bit data");
+        return EC_IllegalParameter;
+    }
+    OFCondition result;
+    unsigned long num16BitEntries = num8BitEntries / 2 + (num8BitEntries % 2);
+    // put 16 bit data together by combining two 8 bit entries into one 16 bit entry
+    Uint16* newData = new Uint16[num16BitEntries];
+    for (unsigned long i = 0; i < num16BitEntries; i++)
+    {
+        if (i != num16BitEntries-1)
+        {
+            newData[i] = OFstatic_cast(Uint16, lutData[i*2] << 8) | lutData[i*2+1];
+        }
+        else
+        {
+            // if odd number of 8 bit entries, only use lower byte of last entry
+            newData[i] = OFstatic_cast(Uint16, lutData[i*2] << 8);
+        }
+    }
+    // Reset last entry (second part of 16 bit word) to 0 if odd number of 8 bit entries
+    if (num8BitEntries % 2)
+    {
+        newData[num16BitEntries-1] &= 0xFF00;
+    }
+    // otherwise also take over last 8 bit entry
+    else
+    {
+        newData[num16BitEntries-1] |= lutData[num8BitEntries-1];
+    }
+    result = m_Item->putAndInsertUint16Array(dataTag, newData, num16BitEntries);
+    delete[] newData;
+    return result;
+}
+
+
+OFCondition IODPaletteColorLUTModule::numEntriesForData(const DcmTagKey& dataTag, Uint16& result)
+{
+    result = 0;
+    OFCondition cond;
+    if (dataTag == DCM_RedPaletteColorLookupTableData)
+    {
+        cond = getRedPaletteColorLookupTableDescriptor(result, 0);
+    }
+    else if (dataTag == DCM_GreenPaletteColorLookupTableData)
+    {
+        cond = getGreenPaletteColorLookupTableDescriptor(result, 0);
+    }
+    else if (dataTag == DCM_BluePaletteColorLookupTableData)
+    {
+        cond = getBluePaletteColorLookupTableDescriptor(result, 0);
+    }
+    else if (dataTag == DCM_SegmentedRedPaletteColorLookupTableData)
+    {
+        cond = getRedPaletteColorLookupTableDescriptor(result, 0);
+    }
+    else if (dataTag == DCM_SegmentedGreenPaletteColorLookupTableData)
+    {
+        cond = getGreenPaletteColorLookupTableDescriptor(result, 0);
+    }
+    else if (dataTag == DCM_SegmentedBluePaletteColorLookupTableData)
+    {
+        cond = getBluePaletteColorLookupTableDescriptor(result, 0);
+    }
+    else
+    {
+        return EC_InvalidTag;
+    }
+    return cond;
+}
index cdba8600b31b4c8cb4457e14dd460eb996b4ea51..43265f4133be170a25e976befa9724f58ae5d3de 100644 (file)
@@ -3,12 +3,15 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmiod_tests
   tchecks.cc
   tcielabutil.cc
   tcodes.cc
+  ticcprofile.cc
   timagepixel.cc
+  tmacro.cc
+  tpalette.cc
   tests.cc
 )
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcmiod_tests dcmiod dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(dcmiod_tests dcmimgle dcmiod dcmdata oflog ofstd)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmiod)
index eb860778a4ef17ef6eef7a8879b54aa0c5f92083..f69dab64576777cd0d801d1e3b23d630d65a0407 100644 (file)
@@ -57,6 +57,7 @@ tchecks.o: tchecks.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../include/dcmtk/dcmiod/iodtypes.h ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../include/dcmtk/dcmiod/iodmacro.h \
@@ -221,7 +222,9 @@ tcodes.o: tcodes.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
- ../include/dcmtk/dcmiod/ioddef.h ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
@@ -278,6 +281,82 @@ tests.o: tests.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h
+ticcprofile.o: ticcprofile.cc \
+ ../../config/include/dcmtk/config/osconfig.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../include/dcmtk/dcmiod/modiccprofile.h \
+ ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/modbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
 timagepixel.o: timagepixel.cc \
  ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmiod/iodimage.h ../include/dcmtk/dcmiod/iodcommn.h \
@@ -323,6 +402,8 @@ timagepixel.o: timagepixel.cc \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../include/dcmtk/dcmiod/modcommoninstanceref.h \
@@ -336,7 +417,6 @@ timagepixel.o: timagepixel.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -376,3 +456,159 @@ timagepixel.o: timagepixel.cc \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
+tmacro.o: tmacro.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/modbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h
+tpalette.o: tpalette.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../include/dcmtk/dcmiod/iodrules.h ../include/dcmtk/dcmiod/iodtypes.h \
+ ../include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../include/dcmtk/dcmiod/modbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
index e3bf28e4f26e4f947ec20546fa0883d457938b8c..67059a32e9b771a1d077096a2470900bb878f438 100644 (file)
@@ -17,15 +17,19 @@ ofstddir = $(top_srcdir)/../ofstd
 oflogdir = $(top_srcdir)/../oflog
 dcmdatadir = $(top_srcdir)/../dcmdata
 dcmioddir = $(top_srcdir)/../dcmiod
+dcmimgledir = $(top_srcdir)/../dcmimgle
 
 LOCALINCLUDES = -I$(dcmioddir)/include -I$(dcmdatadir)/include -I$(oflogdir)/include \
        -I$(ofstddir)/include
 LIBDIRS = -L$(top_srcdir)/libsrc -L$(dcmioddir)/libsrc -L$(dcmdatadir)/libsrc \
-       -L$(oflogdir)/libsrc -L$(ofstddir)/libsrc -L$(oficonvdir)/libsrc
-LOCALLIBS = -ldcmiod -ldcmdata -loflog -lofstd -loficonv \
+       -L$(oflogdir)/libsrc -L$(ofstddir)/libsrc -L$(oficonvdir)/libsrc \
+       -L$(dcmimgledir)/libsrc
+LOCALLIBS = -ldcmiod -ldcmimgle -ldcmdata -loflog -lofstd -loficonv \
        $(TIFFLIBS) $(PNGLIBS) $(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS)
 
-test_objs = tests.o tchecks.o tcielabutil.o tcodes.o timagepixel.o
+test_objs = tests.o tchecks.o tcielabutil.o tcodes.o ticcprofile.o \
+       timagepixel.o tmacro.o tpalette.o
+
 objs = tests.o $(test_objs)
 progs = tests
 
index 544883ac7f4e71f1b57fb6615ba5468e78edc5b2..6a88c60202475b8aaf467ee0b51ac03115d53f2f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2024, OFFIS e.V.
+ *  Copyright (C) 2024-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -11,7 +11,7 @@
  *    D-26121 Oldenburg, Germany
  *
  *
- *  Module:  dcmect
+ *  Module:  dcmiod
  *
  *  Author:  Michael Onken
  *
index 83c0084195c5e50408cec1a3cc28496d0a434675..230fbcb10f75faf42d43bf7dacf4181821db11f8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, OFFIS e.V.
+ *  Copyright (C) 2016-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -28,6 +28,11 @@ OFTEST_REGISTER(dcmiod_component_check_missing_value);
 OFTEST_REGISTER(dcmiod_component_check_vm_violated);
 OFTEST_REGISTER(dcmiod_component_check_vr_violated);
 OFTEST_REGISTER(dcmiod_codes);
+OFTEST_REGISTER(dcmiod_content_identification_macro);
+OFTEST_REGISTER(dcmiod_icc_profile_module);
 OFTEST_REGISTER(dcmiod_imagepixel);
 OFTEST_REGISTER(dcmiod_tcielabutil);
+OFTEST_REGISTER(dcmiod_palette_color_lut_module);
+OFTEST_REGISTER(dcmiod_palette_color_lut_module_segmented);
+OFTEST_REGISTER(dcmiod_palette_color_lut_module_extra_checks);
 OFTEST_MAIN("dcmiod")
diff --git a/dcmiod/tests/ticcprofile.cc b/dcmiod/tests/ticcprofile.cc
new file mode 100644 (file)
index 0000000..faebfd4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmiod
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Tests for dcmiod's checks
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/oflog/oflog.h"
+#include "dcmtk/dcmdata/dcdict.h"
+#include "dcmtk/dcmiod/modiccprofile.h"
+#include "dcmtk/ofstd/oftest.h"
+
+
+static const Uint8 ICC_LENGTH = 100;
+static const OFString COLOR_SPACE("SRGB");
+
+static void fillICCProfile(IODICCProfileModule& mod);
+static void checkICCProfile(IODICCProfileModule& mod);
+static void checkReadWriteICCProfile(IODICCProfileModule& mod);
+
+static OFLogger tLog = OFLog::getLogger("dcmtk.test.ticcprofile");
+
+
+/** Make sure dictionary is loaded
+ *  @return OFTrue if dictionary is loaded, OFFalse otherwise
+ */
+static OFBool checkDictionary()
+{
+     // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return OFFalse;
+    }
+    return OFTrue;
+}
+
+OFTEST(dcmiod_icc_profile_module)
+{
+    OFCHECK(checkDictionary());
+    IODICCProfileModule mod;
+
+    fillICCProfile(mod);
+    checkICCProfile(mod);
+    checkReadWriteICCProfile(mod);
+}
+
+
+static void fillICCProfile(IODICCProfileModule& mod)
+{
+    Uint8* iccProfile = new Uint8[ICC_LENGTH];
+    for (Uint8 i = 0; i < ICC_LENGTH; i++)
+    {
+        iccProfile[i] = i;
+    }
+    OFCHECK(mod.setICCProfile(iccProfile, ICC_LENGTH, OFTrue /* check */).good());
+    OFCHECK(mod.setColorSpace(COLOR_SPACE, OFTrue /* check */).good());
+
+    delete[] iccProfile;
+}
+
+
+static void checkICCProfile(IODICCProfileModule& mod)
+{
+    const Uint8* iccProfile = NULL;
+    Uint32 length = 0;
+    OFCHECK(mod.getICCProfile(iccProfile, length).good());
+    OFCHECK(length == ICC_LENGTH);
+    for (unsigned long i = 0; i < ICC_LENGTH; i++)
+    {
+        OFCHECK(iccProfile[i] == i);
+    }
+    OFString colorSpace;
+    OFCHECK(mod.getColorSpace(colorSpace).good());
+    OFCHECK(colorSpace == COLOR_SPACE);
+    delete [] iccProfile; // clean up, this is a copy
+}
+
+
+static void checkReadWriteICCProfile(IODICCProfileModule& mod)
+{
+    // Write to item and check all values using dcmdata API
+    DcmItem item;
+    OFCHECK(mod.write(item).good());
+    const Uint8* profile = NULL;
+    unsigned long count = 0;;
+    OFCHECK(item.findAndGetUint8Array(DCM_ICCProfile, profile, &count).good());
+    OFCHECK(count == ICC_LENGTH);
+    for (unsigned long i = 0; i < ICC_LENGTH; i++)
+    {
+        OFCHECK(profile[i] == i);
+    }
+    OFString colorSpace;
+    OFCHECK(item.findAndGetOFString(DCM_ColorSpace, colorSpace).good());
+    OFCHECK(colorSpace == COLOR_SPACE);
+
+    // Read from item and check all values from module class
+    IODICCProfileModule mod2;
+    OFCHECK(mod2.read(item).good());
+    checkICCProfile(mod2);
+}
\ No newline at end of file
diff --git a/dcmiod/tests/tmacro.cc b/dcmiod/tests/tmacro.cc
new file mode 100644 (file)
index 0000000..b4ffa97
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmiod
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Tests for dcmiod macros
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/dcmiod/iodmacro.h"
+
+
+OFTEST(dcmiod_content_identification_macro)
+{
+    ContentIdentificationMacro macro;
+    OFCHECK((macro.check(OFTrue /* quiet */).bad()));
+
+    OFCHECK(macro.setContentCreatorName("OC").good());
+    OFCHECK(macro.setContentDescription("Test Description").good());
+    OFCHECK(macro.setContentLabel("TEST_LABEL").good());
+    OFCHECK(macro.setInstanceNumber("42").good());
+
+    OFCHECK(macro.check(OFTrue /* quiet */).good());
+    OFString str;
+
+    // Check all strings
+    OFCHECK(macro.getContentCreatorName(str).good());
+    OFCHECK(str == "OC");
+    OFCHECK(macro.getContentDescription(str).good());
+    OFCHECK(str == "Test Description");
+    OFCHECK(macro.getContentLabel(str).good());
+    OFCHECK(str == "TEST_LABEL");
+    OFCHECK(macro.getInstanceNumber(str).good());
+    OFCHECK(str == "42");
+
+    // Write and re-read
+    DcmItem item;
+    OFCHECK(macro.write(item).good());
+    ContentIdentificationMacro macro2;
+    OFCHECK(macro2.read(item).good());
+    OFCHECK(macro2.check(OFTrue /* quiet */).good());
+
+    // Check strings in macro2
+    OFCHECK(macro2.getContentCreatorName(str).good());
+    OFCHECK(str == "OC");
+    OFCHECK(macro2.getContentDescription(str).good());
+    OFCHECK(str == "Test Description");
+    OFCHECK(macro2.getContentLabel(str).good());
+    OFCHECK(str == "TEST_LABEL");
+    OFCHECK(macro2.getInstanceNumber(str).good());
+    OFCHECK(str == "42");
+}
diff --git a/dcmiod/tests/tpalette.cc b/dcmiod/tests/tpalette.cc
new file mode 100644 (file)
index 0000000..0a5f611
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmiod
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Tests for dcmiod's checks
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+#include "dcmtk/oflog/oflog.h"
+#include "dcmtk/dcmdata/dcdict.h"
+#include "dcmtk/dcmiod/modpalettecolorlut.h"
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/ofstd/oflimits.h"
+#include "dcmtk/ofstd/ofdiag.h"
+
+
+template<typename T> static T* makePixelData(unsigned long& num_entries);
+template<typename T> static OFBool verifyPixelData(T* dataFound, T* data, const unsigned long& num_entries);
+template<typename T> static void createNonSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data);
+template<typename T> static void checkNonSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data);
+
+template<typename T> static void createSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data);
+template<typename T> static void checkSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data);
+
+
+
+static void clear(IODPaletteColorLUTModule& mod);
+
+static OFLogger tLog = OFLog::getLogger("dcmtk.test.tpalette");
+
+/** Make sure dictionary is loaded
+ *  @return OFTrue if dictionary is loaded, OFFalse otherwise
+ */
+static OFBool checkDictionary()
+{
+     // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return OFFalse;
+    }
+    return OFTrue;
+}
+
+OFTEST(dcmiod_palette_color_lut_module)
+{
+    OFCHECK(checkDictionary());
+    IODPaletteColorLUTModule mod;
+
+    // 16 Bit data
+    unsigned long num_entries = 65535;
+    Uint8 num_bits = 16;
+    const Uint16* data16bit = makePixelData<Uint16>(num_entries);
+    createNonSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data16bit);
+    checkNonSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data16bit);
+    clear(mod);
+    delete[] data16bit;
+
+    // 16 bit max entries
+    num_entries = 65536;
+    num_bits = 16;
+    const Uint16* data16bitMax = makePixelData<Uint16>(num_entries);
+    createNonSegmentedPaletteModule(mod, num_bits, 0, data16bitMax);
+    checkNonSegmentedPaletteModule(mod, num_bits, 0, data16bitMax);
+    clear(mod);
+    delete[] data16bitMax;
+
+    // 8 bit data
+    num_entries = 255;
+    num_bits = 8;
+    const Uint8* data8bit = makePixelData<Uint8>(num_entries);
+    createNonSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data8bit);
+    checkNonSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data8bit);
+    clear(mod);
+    delete[] data8bit;
+
+    // 8 bit max entries
+    num_entries = 256;
+    num_bits = 8;
+    const Uint8* data8bitMax = makePixelData<Uint8>(num_entries);
+    createNonSegmentedPaletteModule(mod, num_bits, 0, data8bitMax);
+    checkNonSegmentedPaletteModule(mod, num_bits, 0, data8bitMax);
+    clear(mod);
+    delete[] data8bitMax;
+}
+
+OFTEST(dcmiod_palette_color_lut_module_segmented)
+{
+    OFCHECK(checkDictionary());
+    IODPaletteColorLUTModule mod;
+
+    // 16 Bit data
+    unsigned long num_entries = 65535;
+    Uint8 num_bits = 16;
+    const Uint16* data16bit = makePixelData<Uint16>(num_entries);
+    createSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data16bit);
+    checkSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data16bit);
+    clear(mod);
+    delete[] data16bit;
+
+    // 16 bit max entries
+    num_entries = 65536;
+    num_bits = 16;
+    const Uint16* data16bitMax = makePixelData<Uint16>(num_entries);
+    createSegmentedPaletteModule(mod, num_bits, 0, data16bitMax);
+    checkSegmentedPaletteModule(mod, num_bits, 0, data16bitMax);
+    clear(mod);
+    delete[] data16bitMax;
+
+    // 8 bit data
+    num_entries = 255;
+    num_bits = 8;
+    const Uint8* data8bit = makePixelData<Uint8>(num_entries);
+    createSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data8bit);
+    checkSegmentedPaletteModule(mod, num_bits, OFstatic_cast(Uint16, num_entries), data8bit);
+    clear(mod);
+    delete[] data8bit;
+
+    // 8 bit max entries
+    num_entries = 256;
+    num_bits = 8;
+    const Uint8* data8bitMax = makePixelData<Uint8>(num_entries);
+    createSegmentedPaletteModule(mod, num_bits, 0, data8bitMax);
+    checkSegmentedPaletteModule(mod, num_bits, 0, data8bitMax);
+    clear(mod);
+    delete[] data8bitMax;
+}
+
+OFTEST(dcmiod_palette_color_lut_module_extra_checks)
+{
+    // 16 bit data with 8 bit descriptor fails
+    IODPaletteColorLUTModule mod;
+    unsigned long num_entries = 255;
+    const Uint16* data16bit = makePixelData<Uint16>(num_entries);
+    OFCHECK(mod.setRedPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 8).good());
+    OFCHECK(mod.setGreenPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 8).good());
+    OFCHECK(mod.setBluePaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 8).good());
+    // Now try to set 16 LUT Data
+    OFCHECK(mod.setRedPaletteColorLookupTableData(data16bit, num_entries).bad());
+    OFCHECK(mod.setGreenPaletteColorLookupTableData(data16bit, num_entries).bad());
+    OFCHECK(mod.setBluePaletteColorLookupTableData(data16bit, num_entries).bad());
+    delete[] data16bit;
+    mod.clearData();
+
+    // 8 bit data with 16 bit descriptor fails
+    num_entries = 65535;
+    Uint8* data8bit = new Uint8[num_entries];
+    memset(data8bit, 0, num_entries * sizeof(Uint8)); // vallues will be not exercised at all
+    OFCHECK(mod.setRedPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    OFCHECK(mod.setGreenPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    OFCHECK(mod.setBluePaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    // Now try to set 8 LUT Data
+    OFCHECK(mod.setRedPaletteColorLookupTableData(data8bit, num_entries).bad());
+    OFCHECK(mod.setGreenPaletteColorLookupTableData(data8bit, num_entries).bad());
+    OFCHECK(mod.setBluePaletteColorLookupTableData(data8bit, num_entries).bad());
+    delete[] data8bit;
+
+    // mix of segment and non segment data fails
+    num_entries = 65535;
+    DcmItem item;
+    data16bit = makePixelData<Uint16>(num_entries);
+    OFCHECK(mod.setRedPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    OFCHECK(mod.setGreenPaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    OFCHECK(mod.setBluePaletteColorLookupTableDescriptor(OFstatic_cast(Uint16, num_entries), 0, 16).good());
+    OFCHECK(mod.setSegmentedRedPaletteColorLookupTableData(data16bit, num_entries).good());
+    OFCHECK(mod.setSegmentedGreenPaletteColorLookupTableData(data16bit, num_entries).good());
+    OFCHECK(mod.setSegmentedBluePaletteColorLookupTableData(data16bit, num_entries).good());
+    // this does not make sense:
+    OFCHECK(mod.setRedPaletteColorLookupTableData(data16bit, num_entries).good());
+    OFCHECK(mod.setGreenPaletteColorLookupTableData(data16bit, num_entries).good());
+    OFCHECK(mod.setBluePaletteColorLookupTableData(data16bit, num_entries).good());
+    OFCHECK(mod.write(item).bad());
+    delete[] data16bit;
+
+}
+
+
+template<typename T>
+static T* makePixelData(unsigned long& num_entries)
+{
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_VISUAL_STUDIO_CONSTANT_EXPRESSION_WARNING
+    if (!OFnumeric_limits<T>::is_signed && (OFnumeric_limits<T>::max() < num_entries - 1))
+    {
+        OFCHECK_MSG(OFFalse, "Internal error, cannot create pixel data for given type T, too many entries.");
+    }
+    else if (OFnumeric_limits<T>::is_signed && (OFstatic_cast(unsigned long, OFnumeric_limits<T>::max()) / 2 > num_entries - 1))
+    {
+        OFCHECK_MSG(OFFalse, "Internal error, cannot create pixel data for given type T, too many entries.");
+    }
+#include DCMTK_DIAGNOSTIC_POP
+
+    T* data = new T[num_entries];
+    for (unsigned long i = 0; i < num_entries; i++)
+    {
+        // Casts are safe since we check the limits above,
+        // and this way the compiler does not complain about narrowing conversions
+        if (OFnumeric_limits<T>::is_signed)
+            data[i] = OFstatic_cast(T, i - num_entries / 2);
+        else
+            data[i] = OFstatic_cast(T, i);
+    }
+    return data;
+}
+
+template<typename T>
+static OFBool verifyPixelData(T* dataFound, T* data, const unsigned long& num_entries)
+{
+    if (!data || !dataFound)
+    {
+        return OFFalse;
+    }
+
+    for (unsigned int i = 0; i < num_entries; i++)
+    {
+        if (dataFound[i] != data[i])
+        {
+            OFLOG_DEBUG(tLog, "Pixel data at index " << OFstatic_cast(Uint16, i) << " is " << OFstatic_cast(Uint16, dataFound[i]) << " but should be " << OFstatic_cast(Uint16, data[i]));
+            return OFFalse;
+        }
+    }
+    return OFTrue;
+}
+
+static void clear(IODPaletteColorLUTModule& mod)
+{
+    mod.clearData();
+    OFCHECK(mod.numBits() == 0);
+}
+
+
+template<typename T>
+static void createNonSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data)
+{
+    OFCHECK_MSG(mod.setRedPaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Red Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setGreenPaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Green Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setBluePaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Blue Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setPaletteColorLookupTableUID("1.2.3.4").good(), "Cannot set Palette Color Lookup Table UID (1.2.3.4)");
+
+    OFCHECK_MSG(mod.setRedPaletteColorLookupTableData(data, numEntries).good(), "Cannot set Red Palette Color Lookup Table Data");
+    OFCHECK_MSG(mod.setGreenPaletteColorLookupTableData(data, numEntries).good(), "Cannot set Green Palette Color Lookup Table Data");
+    OFCHECK_MSG(mod.setBluePaletteColorLookupTableData(data, numEntries).good(), "Cannot set Blue Palette Color Lookup Table Data");
+}
+
+template<typename T>
+static void createSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data)
+{
+    OFCHECK_MSG(mod.setRedPaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Red Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setGreenPaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Green Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setBluePaletteColorLookupTableDescriptor(numEntries, 0, bits).good(), "Cannot set Blue Palette Color Lookup Table Descriptor");
+    OFCHECK_MSG(mod.setPaletteColorLookupTableUID("1.2.3.4").good(), "Cannot set Palette Color Lookup Table UID (1.2.3.4)");
+
+    OFCHECK_MSG(mod.setSegmentedRedPaletteColorLookupTableData(data, numEntries).good(), "Cannot set Segmented Red Palette Color Lookup Table Data");
+    OFCHECK_MSG(mod.setSegmentedGreenPaletteColorLookupTableData(data, numEntries).good(), "Cannot set Segmented Green Palette Color Lookup Table Data");
+    OFCHECK_MSG(mod.setSegmentedBluePaletteColorLookupTableData(data, numEntries).good(), "Cannot set Segmented Blue Palette Color Lookup Table Data");
+}
+
+
+template<typename T>
+static void checkNonSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data)
+{
+    DcmItem item;
+    OFString uid;
+    Uint16 d1,d2,d3;
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK_MSG(mod.write(item).good(), "Cannot write Palette Color Lookup Table Module to DcmItem");
+    OFCHECK_MSG(mod.numBits() == bits, "getBits() returns wrong value for Palette Color Lookup Table Module");
+    OFCHECK_MSG(mod.getPaletteColorLookupTableUID(uid).good(), "Cannot get Palette Color Lookup Table UID");
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+
+    OFCHECK(uid == "1.2.3.4");
+    // 16 bit data
+    if (bits == 16)
+    {
+        unsigned long entriesFound = 0;
+        const Uint16 *dataFound16 = NULL;
+        OFCHECK(mod.getRedPaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16; dataFound16 = NULL;
+        OFCHECK(mod.getGreenPaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16; dataFound16 = NULL;
+        OFCHECK(mod.getBluePaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16;
+    }
+    // 8 bit data
+    else if (bits == 8)
+    {
+        unsigned long entriesFound = 0;
+        const Uint8 *dataFound8 = NULL;
+        OFCHECK(mod.getRedPaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8; dataFound8 = NULL;
+        OFCHECK(mod.getGreenPaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8; dataFound8 = NULL;
+        OFCHECK(mod.getBluePaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8;
+    }
+    else
+    {
+        OFCHECK_FAIL("Unsupported bit depth");
+    }
+}
+
+
+template<typename T>
+static void checkSegmentedPaletteModule(IODPaletteColorLUTModule& mod, Uint8 bits, const Uint16 numEntries, const T*& data)
+{
+    DcmItem item;
+    OFString uid;
+    unsigned long entriesFound = 0;
+    Uint16 d1,d2,d3;
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK_MSG(mod.write(item).good(), "Cannot write (segmented) Palette Color Lookup Table Module to DcmItem");
+    OFCHECK_MSG(mod.numBits() == bits, "getBits() returns wrong value for Palette Color Lookup Table Module");
+    OFCHECK_MSG(mod.getPaletteColorLookupTableUID(uid).good(), "Cannot get Palette Color Lookup Table UID");
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getRedPaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getGreenPaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+    d1 = d2 = d3 = 1; // not used in test data
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d1, 0).good());
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d2, 1).good());
+    OFCHECK(mod.getBluePaletteColorLookupTableDescriptor(d3, 2).good());
+    OFCHECK(d1 == numEntries);
+    OFCHECK(d2 == 0);
+    OFCHECK(d3 == bits);
+
+    OFCHECK(uid == "1.2.3.4");
+    // 16 bit data
+    if (bits == 16)
+    {
+        const Uint16 *dataFound16 = NULL;
+        OFCHECK(mod.getSegmentedRedPaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16; dataFound16 = NULL;
+        OFCHECK(mod.getSegmentedGreenPaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16; dataFound16 = NULL;
+        OFCHECK(mod.getSegmentedBluePaletteColorLookupTableData(dataFound16, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 65536) : numEntries));
+        OFCHECK(verifyPixelData(dataFound16, (const Uint16*)data, numEntries));
+        delete[] dataFound16;
+    }
+    // 8 bit data
+    else if (bits == 8)
+    {
+        const Uint8 *dataFound8 = NULL;
+        OFCHECK(mod.getSegmentedRedPaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8; dataFound8 = NULL;
+        OFCHECK(mod.getSegmentedGreenPaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8; dataFound8 = NULL;
+        OFCHECK(mod.getSegmentedBluePaletteColorLookupTableData(dataFound8, entriesFound).good());
+        OFCHECK(entriesFound == ((numEntries == 0) ? OFstatic_cast(unsigned long, 256) : numEntries));
+        OFCHECK(verifyPixelData(dataFound8, (const Uint8*)data, numEntries));
+        delete[] dataFound8;
+    }
+    else
+    {
+        OFCHECK_FAIL("Unsupported bit depth");
+    }
+}
\ No newline at end of file
index 0c9636389bef022214401c59380c9a196f52e27a..9388bd1f5fae8828b0916b3129d79914dca00275 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2022, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -68,6 +68,7 @@ int main(int argc, char *argv[])
   OFBool opt_predictor6WorkaroundEnable = OFFalse;
   OFBool opt_cornellWorkaroundEnable = OFFalse;
   OFBool opt_forceSingleFragmentPerFrame = OFFalse;
+  OFBool opt_preserveBitsStored = OFFalse;
 
   OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Decode JPEG-compressed DICOM file", rcsid);
   OFCommandLine cmd;
@@ -102,6 +103,10 @@ int main(int argc, char *argv[])
       cmd.addOption("--color-by-pixel",      "+px",    "always store color-by-pixel");
       cmd.addOption("--color-by-plane",      "+pl",    "always store color-by-plane");
 
+    cmd.addSubGroup("bits stored:");
+      cmd.addOption("--bits-stored-fix",     "+bs",    "correct inconsistent bits stored value (default)");
+      cmd.addOption("--bits-stored-keep",    "-bs",    "preserve inconsistent bits stored value");
+
     cmd.addSubGroup("SOP Instance UID:");
       cmd.addOption("--uid-default",         "+ud",    "keep same SOP Instance UID (default)");
       cmd.addOption("--uid-always",          "+ua",    "always assign new UID");
@@ -169,6 +174,11 @@ int main(int argc, char *argv[])
       if (cmd.findOption("--color-by-plane")) opt_planarconfig = EPC_colorByPlane;
       cmd.endOptionBlock();
 
+      cmd.beginOptionBlock();
+      if (cmd.findOption("--bits-stored-fix")) opt_preserveBitsStored = OFFalse;
+      if (cmd.findOption("--bits-stored-keep")) opt_preserveBitsStored = OFTrue;
+      cmd.beginOptionBlock();
+
       cmd.beginOptionBlock();
       if (cmd.findOption("--conv-photometric")) opt_decompCSconversion = EDC_photometricInterpretation;
       if (cmd.findOption("--conv-lossy")) opt_decompCSconversion = EDC_lossyOnly;
@@ -266,7 +276,8 @@ int main(int argc, char *argv[])
       opt_planarconfig,
       opt_predictor6WorkaroundEnable,
       opt_cornellWorkaroundEnable,
-      opt_forceSingleFragmentPerFrame);
+      opt_forceSingleFragmentPerFrame,
+      opt_preserveBitsStored);
 
     /* make sure data dictionary is loaded */
     if (!dcmDataDict.isDictionaryLoaded())
index 41079df7940e9a0f9fcbc618acb00451e565d155..2d7c44f64ba9e11e9276b0d05544d5aaf7440ae2 100644 (file)
@@ -707,6 +707,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmcjpeg_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 52898187cb6a906a4e49b7d85db150168eb24bb9..45de63bd51a68699752bfe91d746c0b470534e48 100644 (file)
@@ -147,6 +147,21 @@ planar configuration:
   # If the compressed image is a color image, store in color-by-plane
   # planar configuration.
 
+bits stored:
+
+  +bs  --bits-stored-fix
+         correct inconsistent bits stored value (default)
+
+  # If the value of BitsStored in the compressed bitstream is smaller
+  # than the value in the DICOM dataset, update the value in the dataset.
+
+  -bs  --bits-stored-keep
+         preserve inconsistent bits stored value
+
+  # Keep the value of BitsStored even if inconsistent with the
+  # compressed bitstream. This may help in correctly decoding some
+  # defective images.
+
 SOP Instance UID:
 
   +ud   --uid-default
@@ -347,6 +362,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmdjpeg_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 8714ecd36a27c1e1a2ed8b3584b57c0df780d576..7a7d65c27cb0e06220baf0c9256ea16e60b8c59b 100644 (file)
@@ -23,6 +23,6 @@ the same command line parameters, and more.
 
 \section dcmj2pnm_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7ffce8f14cb706f66dea3b3b19aa7a6606b5651a..eaa201f078aae68d64ebaf06364c5df3920b7c5f 100644 (file)
@@ -508,6 +508,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmmkdir_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7c31575d838712859b309ea62ef88c0218b9bd43..0d02954583cb2d2cd6bdf30aa67a046b25eefef4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2020, OFFIS e.V.
+ *  Copyright (C) 2001-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -177,6 +177,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
index 7f3b6bc43ef2b7248385e091dcc3b34d04ba067a..553df6e305f9a88ea686640d88ef69a70dbe380f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2020, OFFIS e.V.
+ *  Copyright (C) 2001-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -181,6 +181,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
index b8f234c267d3710b29cc0a32c4983786cba677f4..7a620a84d4f14a20490caa870240561765e8effc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2018, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -68,6 +68,7 @@ public:
    *  @param pAcrNemaCompatibility accept old ACR-NEMA images without photometric interpretation
    *    (only "pseudo" lossless encoder)
    *  @param pTrueLosslessMode Enables true lossless compression (replaces old "pseudo lossless" encoder)
+   *  @param setPreserveBitsStored  preserve BitsStored when decompressing even if inconsistent with J2K bitstream
    */
   DJCodecParameter(
     E_CompressionColorSpaceConversion pCompressionCSConversion,
@@ -97,7 +98,8 @@ public:
     OFBool pUseModalityRescale = OFFalse,
     OFBool pAcceptWrongPaletteTags = OFFalse,
     OFBool pAcrNemaCompatibility = OFFalse,
-    OFBool pTrueLosslessMode = OFTrue);
+    OFBool pTrueLosslessMode = OFTrue,
+    OFBool setPreserveBitsStored = OFFalse);
 
   /// copy constructor
   DJCodecParameter(const DJCodecParameter& arg);
@@ -323,6 +325,15 @@ public:
     return forceSingleFragmentPerFrame;
   }
 
+  /** returns flag indicating whether to preserve the
+   *  value of BitsStored even if inconsistent with the
+   *  compressed bitstream.
+   */
+  OFBool getPreserveBitsStored() const
+  {
+    return setPreserveBitsStored_;
+  }
+
 private:
 
   /// private undefined copy assignment operator
@@ -427,6 +438,9 @@ private:
    */
   OFBool forceSingleFragmentPerFrame;
 
+  /// flag indicating whether BitsStored should be preserved when decompressing even if inconsistent with the J2K bitstream
+  OFBool setPreserveBitsStored_;
+
 };
 
 
index d2d5c791c49d23f7f7ef3be75a2971a0ac62799c..f6468c97a595adb10a53514738040780a6597359 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2018, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -52,6 +52,7 @@ public:
    *    Huffman table overflow
    *  @param pForceSingleFragmentPerFrame while decompressing a multiframe image,
    *    assume one fragment per frame even if the JPEG data for some frame is incomplete
+   *  @param setPreserveBitsStored preserve BitsStored when decompressing even if inconsistent with J2K bitstream
    */
   static void registerCodecs(
     E_DecompressionColorSpaceConversion pDecompressionCSConversion = EDC_photometricInterpretation,
@@ -59,7 +60,8 @@ public:
     E_PlanarConfiguration pPlanarConfiguration = EPC_default,
     OFBool predictor6WorkaroundEnable = OFFalse,
     OFBool cornellWorkaroundEnable = OFFalse,
-    OFBool pForceSingleFragmentPerFrame = OFFalse);
+    OFBool pForceSingleFragmentPerFrame = OFFalse,
+    OFBool setPreserveBitsStored = OFFalse);
 
   /** deregisters decoders.
    *  Attention: Must not be called while other threads might still use
index a6fcb5ddcf6dd2d3cb39fe69b4578f41b02863f9..d50305ccdff085f70d309ba6d94216526167b104 100644 (file)
 
 #include "dcmtk/config/osconfig.h"
 
-/* We assume ANSI C and don't support DOS, 
- * so the following settings need not be tested 
+/* We assume ANSI C and don't support DOS,
+ * so the following settings need not be tested
  */
-#define HAVE_PROTOTYPES 
-#define HAVE_UNSIGNED_CHAR 
-#define HAVE_UNSIGNED_SHORT 
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
 #undef NEED_FAR_POINTERS
 #undef INCOMPLETE_TYPES_BROKEN
 
@@ -38,9 +38,7 @@
 #define CHAR_IS_UNSIGNED
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #define NEED_SYS_TYPES_H
-#endif
 
 /* must always be defined for our implementation */
 #define NEED_SHORT_EXTERNAL_NAMES
index f564f09be03d81bcdb357a5c22699fdad15a0949..3cdeec1da5f44e99159151542c19602d697d07fb 100644 (file)
@@ -191,7 +191,6 @@ format_message (j_common_ptr cinfo, char * buffer)
   }
 
   /* Format the message into the passed buffer */
-#ifdef HAVE_VSNPRINTF
   if (isstring)
     snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s);
   else
@@ -200,16 +199,6 @@ format_message (j_common_ptr cinfo, char * buffer)
         err->msg_parm.i[2], err->msg_parm.i[3],
         err->msg_parm.i[4], err->msg_parm.i[5],
         err->msg_parm.i[6], err->msg_parm.i[7]);
-#else /* HAVE_VSNPRINTF */
-  if (isstring)
-    sprintf(buffer, msgtext, err->msg_parm.s);
-  else
-    sprintf(buffer, msgtext,
-        err->msg_parm.i[0], err->msg_parm.i[1],
-        err->msg_parm.i[2], err->msg_parm.i[3],
-        err->msg_parm.i[4], err->msg_parm.i[5],
-        err->msg_parm.i[6], err->msg_parm.i[7]);
-#endif /* HAVE_VSNPRINTF */
 }
 
 
index a6fcb5ddcf6dd2d3cb39fe69b4578f41b02863f9..d50305ccdff085f70d309ba6d94216526167b104 100644 (file)
 
 #include "dcmtk/config/osconfig.h"
 
-/* We assume ANSI C and don't support DOS, 
- * so the following settings need not be tested 
+/* We assume ANSI C and don't support DOS,
+ * so the following settings need not be tested
  */
-#define HAVE_PROTOTYPES 
-#define HAVE_UNSIGNED_CHAR 
-#define HAVE_UNSIGNED_SHORT 
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
 #undef NEED_FAR_POINTERS
 #undef INCOMPLETE_TYPES_BROKEN
 
@@ -38,9 +38,7 @@
 #define CHAR_IS_UNSIGNED
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #define NEED_SYS_TYPES_H
-#endif
 
 /* must always be defined for our implementation */
 #define NEED_SHORT_EXTERNAL_NAMES
index 1ad6a6e4d886dc026594916b9bdb24267bf1e33c..2310eae726e2f9ba5589ef5d115671efe88d657f 100644 (file)
@@ -191,7 +191,6 @@ format_message (j_common_ptr cinfo, char * buffer)
   }
 
   /* Format the message into the passed buffer */
-#ifdef HAVE_VSNPRINTF
   if (isstring)
     snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s);
   else
@@ -200,16 +199,6 @@ format_message (j_common_ptr cinfo, char * buffer)
         err->msg_parm.i[2], err->msg_parm.i[3],
         err->msg_parm.i[4], err->msg_parm.i[5],
         err->msg_parm.i[6], err->msg_parm.i[7]);
-#else /* HAVE_VSNPRINTF */
-  if (isstring)
-    sprintf(buffer, msgtext, err->msg_parm.s);
-  else
-    sprintf(buffer, msgtext,
-        err->msg_parm.i[0], err->msg_parm.i[1],
-        err->msg_parm.i[2], err->msg_parm.i[3],
-        err->msg_parm.i[4], err->msg_parm.i[5],
-        err->msg_parm.i[6], err->msg_parm.i[7]);
-#endif /* HAVE_VSNPRINTF */
 }
 
 
index a6fcb5ddcf6dd2d3cb39fe69b4578f41b02863f9..d50305ccdff085f70d309ba6d94216526167b104 100644 (file)
 
 #include "dcmtk/config/osconfig.h"
 
-/* We assume ANSI C and don't support DOS, 
- * so the following settings need not be tested 
+/* We assume ANSI C and don't support DOS,
+ * so the following settings need not be tested
  */
-#define HAVE_PROTOTYPES 
-#define HAVE_UNSIGNED_CHAR 
-#define HAVE_UNSIGNED_SHORT 
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
 #undef NEED_FAR_POINTERS
 #undef INCOMPLETE_TYPES_BROKEN
 
@@ -38,9 +38,7 @@
 #define CHAR_IS_UNSIGNED
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #define NEED_SYS_TYPES_H
-#endif
 
 /* must always be defined for our implementation */
 #define NEED_SHORT_EXTERNAL_NAMES
index d87569de5e9809adfbff0987a6e2f3b04f76bca4..3e873630963445a0e85219dd762c753ce19adb7c 100644 (file)
@@ -191,7 +191,6 @@ format_message (j_common_ptr cinfo, char * buffer)
   }
 
   /* Format the message into the passed buffer */
-#ifdef HAVE_VSNPRINTF
   if (isstring)
     snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s);
   else
@@ -200,16 +199,6 @@ format_message (j_common_ptr cinfo, char * buffer)
         err->msg_parm.i[2], err->msg_parm.i[3],
         err->msg_parm.i[4], err->msg_parm.i[5],
         err->msg_parm.i[6], err->msg_parm.i[7]);
-#else /* HAVE_VSNPRINTF */
-  if (isstring)
-    sprintf(buffer, msgtext, err->msg_parm.s);
-  else
-    sprintf(buffer, msgtext,
-        err->msg_parm.i[0], err->msg_parm.i[1],
-        err->msg_parm.i[2], err->msg_parm.i[3],
-        err->msg_parm.i[4], err->msg_parm.i[5],
-        err->msg_parm.i[6], err->msg_parm.i[7]);
-#endif /* HAVE_VSNPRINTF */
 }
 
 
index 2b8c62f5fdbec64fe7a6c374df942679a48b620b..ea86854d541fa09140596a3b55d4a5c546ff0620 100644 (file)
@@ -84,6 +84,7 @@ ddpiimpl.o: ddpiimpl.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didispfn.h \
index 5b0eeea2136f00ea9f1dccd6b483bdfd6766b214..ce379e107b1d8d0be27be2dc7451ea46b77177d7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2024, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -62,6 +62,24 @@ OFBool DJCodecDecoder::canChangeCoding(
 }
 
 
+Uint16 DJCodecDecoder::decodedBitsAllocated(
+    Uint16 /* bitsAllocated */,
+    Uint16 bitsStored) const
+{
+  // this codec does not support images with less than 2 bits per sample
+  if (bitsStored < 2) return 0;
+
+  // for images with 2..8 bits per sample, BitsAllocated will be 8
+  if (bitsStored <= 8) return 8;
+
+  // for images with 9..16 bits per sample, BitsAllocated will be 16
+  if (bitsStored <= 16) return 16;
+
+  // this codec does not support images with more than 16 bits per sample
+  return 0;
+}
+
+
 OFCondition DJCodecDecoder::decode(
     const DcmRepresentationParameter * fromRepParam,
     DcmPixelSequence * pixSeq,
@@ -328,13 +346,13 @@ OFCondition DJCodecDecoder::decode(
                   }
 
                   // Bits Stored cannot be larger than precision
-                  if ((result.good()) && (imageBitsStored > precision))
+                  if ((result.good()) && (imageBitsStored > precision) && (! djcp->getPreserveBitsStored()))
                   {
                     result = OFreinterpret_cast(DcmItem*, dataset)->putAndInsertUint16(DCM_BitsStored, precision);
                   }
 
                   // High Bit cannot be larger than precision - 1
-                  if ((result.good()) && (imageHighBit >= precision))
+                  if ((result.good()) && (imageHighBit >= precision) && (! djcp->getPreserveBitsStored()))
                   {
                     result = OFreinterpret_cast(DcmItem*, dataset)->putAndInsertUint16(DCM_HighBit, OFstatic_cast(Uint16, precision-1));
                   }
@@ -570,6 +588,11 @@ OFCondition DJCodecDecoder::decodeFrame(
                     // decompression is complete, finally adjust byte order if necessary
                     if (jpeg->bytesPerSample() == 1) // we're writing bytes into words
                     {
+                      if ((gLocalByteOrder == EBO_BigEndian) && (frameSize & 1))
+                      {
+                        DCMJPEG_WARN("Size of frame buffer is odd, cannot correct byte order for last pixel value");
+                      }
+
                       result = swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, OFreinterpret_cast(Uint16*, buffer), OFstatic_cast(Uint32, frameSize), sizeof(Uint16));
                     }
                   }
index de973c5db3a0e04ef5babe8a9a79bd896807137b..50ae1abba9a128e5bb39dec438e54f65ee89eb20 100644 (file)
@@ -75,6 +75,14 @@ OFBool DJCodecEncoder::canChangeCoding(
 }
 
 
+Uint16 DJCodecEncoder::decodedBitsAllocated(
+    Uint16 /* bitsAllocated */,
+    Uint16 /* bitsStored */) const
+{
+  return 0;
+}
+
+
 OFCondition DJCodecEncoder::decode(
   const DcmRepresentationParameter * /* fromRepParam */,
   DcmPixelSequence * /* pixSeq */,
index 6c46eb5eb174eacb8bc7390fabf04ad652a054a1..cf7f85a9018857d279c9619d51c67d388b7ddd9e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2018, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -50,7 +50,8 @@ DJCodecParameter::DJCodecParameter(
     OFBool pUseModalityRescale,
     OFBool pAcceptWrongPaletteTags,
     OFBool pAcrNemaCompatibility,
-    OFBool pTrueLosslessMode)
+    OFBool pTrueLosslessMode,
+    OFBool setPreserveBitsStored)
 : DcmCodecParameter()
 , compressionCSConversion(pCompressionCSConversion)
 , decompressionCSConversion(pDecompressionCSConversion)
@@ -80,6 +81,7 @@ DJCodecParameter::DJCodecParameter(
 , predictor6WorkaroundEnabled_(predictor6WorkaroundEnable)
 , cornellWorkaroundEnabled_(cornellWorkaroundEnable)
 , forceSingleFragmentPerFrame(pForceSingleFragmentPerFrame)
+, setPreserveBitsStored_(setPreserveBitsStored)
 {
 }
 
@@ -114,6 +116,7 @@ DJCodecParameter::DJCodecParameter(const DJCodecParameter& arg)
 , predictor6WorkaroundEnabled_(arg.predictor6WorkaroundEnabled_)
 , cornellWorkaroundEnabled_(arg.cornellWorkaroundEnabled_)
 , forceSingleFragmentPerFrame(arg.forceSingleFragmentPerFrame)
+, setPreserveBitsStored_(arg.setPreserveBitsStored_)
 {
 }
 
index 9166c7bc13cff61078026732b06f8a504cd30dbf..f27ccf68548046fb5c4b8c4f257f2bea1787dfc9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2018, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -47,7 +47,8 @@ void DJDecoderRegistration::registerCodecs(
     E_PlanarConfiguration pPlanarConfiguration,
     OFBool predictor6WorkaroundEnable,
     OFBool cornellWorkaroundEnable,
-    OFBool pForceSingleFragmentPerFrame)
+    OFBool pForceSingleFragmentPerFrame,
+    OFBool setPreserveBitsStored)
 {
   if (! registered)
   {
@@ -58,7 +59,12 @@ void DJDecoderRegistration::registerCodecs(
       pPlanarConfiguration,
       predictor6WorkaroundEnable,
       cornellWorkaroundEnable,
-      pForceSingleFragmentPerFrame);
+      pForceSingleFragmentPerFrame,
+      OFFalse, 0, 0, 0, OFTrue,
+      ESS_444, OFFalse, OFFalse,
+      0, 0, 0.0, 0.0, 0, 0, 0, 0,
+      OFTrue, OFFalse, OFFalse, OFFalse, OFTrue,
+      setPreserveBitsStored);
 
     if (cp)
     {
index f55910465860f6f23d968e6e57384357d4a5897d..c8719f8922ab6cf72678d9c22e88bd50df904dc6 100644 (file)
@@ -8,5 +8,5 @@ endforeach()
 
 # make sure executables are linked to the corresponding libraries
 foreach(PROGRAM dcmcjpls dcmdjpls dcml2pnm)
-  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmjpls dcmtkcharls dcmimage dcmimgle dcmdata oflog ofstd ofstd)
+  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmjpls dcmtkcharls dcmimage)
 endforeach()
index d5d06560252bf4ad2a2c1306af68d3cbe9dc30e8..83cb251217b3357569ad3651b4a77fc1ad18f8a3 100644 (file)
@@ -387,6 +387,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmcjpls_copyright COPYRIGHT
 
-Copyright (C) 2009-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2009-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 9e7eee3feed820a42566e04a653a73addd235e86..93c516fd00820c8040dd38d8aa8014003d99853f 100644 (file)
@@ -280,6 +280,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmdjpls_copyright COPYRIGHT
 
-Copyright (C) 2009-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2009-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 86d162fc5028b182c6bdf6ae6afc6feed33cc1fd..4cd8445122e7cda97fb64e8c0fd10db86795c17a 100644 (file)
@@ -23,6 +23,6 @@ the same command line parameters, and more.
 
 \section dcml2pnm_copyright COPYRIGHT
 
-Copyright (C) 2001-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2001-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 611d9b4d68fc1675a6e781c18409cf3266d23f21..099186b6e5ddbf7941ef61e79996af5a00a5f186 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2020, OFFIS e.V.
+ *  Copyright (C) 2007-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -170,6 +170,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
@@ -239,6 +252,45 @@ private:
     Uint16 imageSamplesPerPixel,
     Uint16 bytesPerSample);
 
+  /** decompresses a single frame from the given pixel sequence and
+   *  stores the result in the given buffer, without adjusting byte order
+   *  @param fromPixSeq compressed pixel sequence
+   *  @param cp codec parameters for this codec
+   *  @param dataset pointer to dataset in which pixel data element is contained
+   *  @param frameNo number of frame, starting with 0 for the first frame
+   *  @param startFragment index of the compressed fragment that contains
+   *    all or the first part of the compressed bitstream for the given frameNo.
+   *    Upon successful return this parameter is updated to contain the index
+   *    of the first compressed fragment of the next frame.
+   *    When unknown, zero should be passed. In this case the decompression
+   *    algorithm will try to determine the index by itself, which will always
+   *    work if frames are decompressed in increasing order from first to last,
+   *    but may fail if frames are decompressed in random order, multiple fragments
+   *    per frame and multiple frames are present in the dataset, and the offset
+   *    table is empty.
+   *  @param buffer pointer to buffer where frame is to be stored
+   *  @param bufSize size of buffer in bytes
+   *  @param imageFrames number of frames in this image
+   *  @param imageColumns number of columns for each frame
+   *  @param imageRows number of rows for each frame
+   *  @param imageSamplesPerPixel number of samples per pixel
+   *  @param bytesPerSample number of bytes per sample
+   *  @return EC_Normal if successful, an error code otherwise.
+   */
+  static OFCondition decodeFrameNoSwap(
+    DcmPixelSequence * fromPixSeq,
+    const DJLSCodecParameter *cp,
+    DcmItem *dataset,
+    Uint32 frameNo,
+    Uint32& startFragment,
+    void *buffer,
+    Uint32 bufSize,
+    Sint32 imageFrames,
+    Uint16 imageColumns,
+    Uint16 imageRows,
+    Uint16 imageSamplesPerPixel,
+    Uint16 bytesPerSample);
+
   /** determines if a given image requires color-by-plane planar configuration
    *  depending on SOP Class UID (DICOM IOD) and photometric interpretation.
    *  All SOP classes defined in the 2003 edition of the DICOM standard or earlier
index 800195059b68dca17e9d70b8c1979c3031b41540..39c3e5d1692abb79c18830c778660eebd7ac58dd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2022, OFFIS e.V.
+ *  Copyright (C) 2007-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -173,6 +173,19 @@ public:
     const E_TransferSyntax oldRepType,
     const E_TransferSyntax newRepType) const;
 
+  /** determines the effective value of BitsAllocated that a dataset will have
+   *  after decompression of an image with the given values for bitsAllocated
+   *  and bitsStored. This may differ from the bitsAllocated parameter for example
+   *  if that value is not a multiple of 8. Returns zero if an image with the
+   *  given parameters cannot be decoded with this codec.
+   *  @param bitsAllocated current value of Bits Allocated
+   *  @param bitsStored current value of Bits Stored
+   *  @return value of BitsAllocated after decompression, 0 if no decompression possible
+   */
+  virtual Uint16 decodedBitsAllocated(
+    Uint16 bitsAllocated,
+    Uint16 bitsStored) const;
+
   /** determine color model of the decompressed image
    *  @param fromParam representation parameter of current compressed
    *    representation, may be NULL
index f49770051b0ed28601baecce0faeb3194f423f1f..be7a970f6ee420fee266abdfa5d48bf2df88066f 100644 (file)
@@ -1,6 +1,6 @@
-// 
-// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 
-// 
+//
+// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
+//
 
 #ifndef CHARLS_ENCODERSTRATEGY
 #define CHARLS_ENCODERSTRATEGY
@@ -24,16 +24,16 @@ public:
      bitpos(0),
      _isFFWritten(false),
      _bytesWritten(0)
-    
+
   {
   }
 
-  virtual ~EncoderStrategy() 
+  virtual ~EncoderStrategy()
   {
   }
 
   LONG PeekByte();
-  
+
   void OnLineBegin(LONG cpixel, void* ptypeBuffer, LONG pixelStride)
   {
     _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride);
@@ -42,7 +42,7 @@ public:
   void OnLineEnd(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) { }
 
     virtual void SetPresets(const JlsCustomParameters& presets) = 0;
-    
+
   virtual size_t EncodeScan(const void* rawData, BYTE **ptr, size_t *size, size_t offset, bool compare) = 0;
 
 protected:
@@ -80,7 +80,7 @@ protected:
 
      valcurrent |= value >> -bitpos;
      Flush();
-   
+
      // A second flush may be required if extra marker-detect bits were needed and not all bits could be written.
      if (bitpos < 0)
      {
@@ -101,7 +101,7 @@ protected:
       AppendToBitStream(0, (bitpos - 1) % 8);
     else
       AppendToBitStream(0, bitpos % 8);
-    
+
     Flush();
     ASSERT(bitpos == 0x20);
   }
@@ -125,27 +125,27 @@ protected:
       {
         write(BYTE(valcurrent >> 24));
         _isFFWritten = (*_position)[_current_offset - 1] == 0xFF;
-        valcurrent = valcurrent << 8;     
+        valcurrent = valcurrent << 8;
         bitpos += 8;
       }
 
     }
-    
+
   }
 
-  size_t GetLength() 
-  { 
-    return _bytesWritten - (bitpos -32)/8; 
+  size_t GetLength()
+  {
+    return _bytesWritten - (bitpos -32)/8;
   }
 
 
   inlinehint void AppendOnesToBitStream(LONG length)
   {
-    AppendToBitStream((1 << length) - 1, length); 
+    AppendToBitStream((1 << length) - 1, length);
   }
 
 
-  OFunique_ptr<DecoderStrategy> _qdecoder; 
+  OFunique_ptr<DecoderStrategy> _qdecoder;
 
 protected:
   JlsParameters _info;
@@ -154,11 +154,7 @@ private:
   static BYTE *re_alloc(BYTE *old_ptr, size_t *old_size)
   {
     size_t new_size = *old_size * 2;
-#ifdef HAVE_STD__NOTHROW
     BYTE *new_ptr = new(std::nothrow) BYTE[new_size];
-#else
-    BYTE *new_ptr = new BYTE[new_size];
-#endif
     if (new_ptr == NULL) {
       throw alloc_fail();
     }
@@ -185,7 +181,7 @@ private:
 
   unsigned int valcurrent;
   LONG bitpos;
-  
+
   // encoding
   BYTE **_position;
   size_t *_size;
index e08249ca71f969b4fbf5c09e1eef2c8ef4c7b50b..851e5829dd28b374e9acea97151c443193010047 100644 (file)
@@ -54,11 +54,10 @@ struct LosslessTraitsImplT
 
 };
 
-// For some weird reason MSVC6 doesn't like these templates.
 // xlC (compiler on AIX) tries to instantiate Triple<Triple<char> > which
 // causes compiler errors and is wrong (other compilers don't instantiate it).
-#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__xlC__)
-#  define DISABLE_SPECIALIZATIONS
+#ifdef __xlC__
+#define DISABLE_SPECIALIZATIONS
 #else
 
 template <class SAMPLE, LONG bpp>
index b4dea20d8de786ec50056a6d3f6bf873f6c8a79a..f13098104c0a269f5a06912670bfad9cf5e59fd1 100644 (file)
@@ -1,6 +1,6 @@
-// 
-// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 
-// 
+//
+// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
+//
 
 #ifndef CHARLS_SCAN
 #define CHARLS_SCAN
@@ -11,7 +11,7 @@
 
 #include "lokuptbl.h"
 
-// This file contains the code for handling a "scan". Usually an image is encoded as a single scan. 
+// This file contains the code for handling a "scan". Usually an image is encoded as a single scan.
 
 #include DCMTK_DIAGNOSTIC_IGNORE_CONST_EXPRESSION_WARNING
 
@@ -21,10 +21,10 @@ extern OFVector<signed char> rgquant10Ll;
 extern OFVector<signed char> rgquant12Ll;
 extern OFVector<signed char> rgquant16Ll;
 //
-// Apply 
+// Apply
 //
 inlinehint LONG ApplySign(LONG i, LONG sign)
-{ return (sign ^ i) - sign; }                                                                  
+{ return (sign ^ i) - sign; }
 
 
 
@@ -58,20 +58,20 @@ inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc)
 
 inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc)
 {
-       // sign trick reduces the number of if statements (branches) 
+       // sign trick reduces the number of if statements (branches)
        LONG sgn = BitWiseSign(Rb - Ra);
 
-       // is Ra between Rc and Rb? 
+       // is Ra between Rc and Rb?
        if ((sgn ^ (Rc - Ra)) < 0)
        {
                return Rb;
-       } 
+       }
        else if ((sgn ^ (Rb - Rc)) < 0)
        {
                return Ra;
        }
 
-       // default case, valid if Rc element of [Ra,Rb] 
+       // default case, valid if Rc element of [Ra,Rb]
        return Ra + Rb - Rc;
 }
 
@@ -110,7 +110,7 @@ public:
 
 public:
 
-         JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : STRATEGY(info), 
+         JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : STRATEGY(info),
          traits(inTraits),
                  _rect(),
                  _width(0),
@@ -120,13 +120,13 @@ public:
                  _RUNindex(0),
                  _pquant(0),
                  _bCompare(0)
-                 
+
          {
                  if (Info().ilv == ILV_NONE)
                  {
                          Info().components = 1;
                  }
-         }     
+         }
 
 
          void SetPresets(const JlsCustomParameters& presets)
@@ -135,9 +135,9 @@ public:
 
                  InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1,
                          presets.T2 != 0 ? presets.T2 : presetDefault.T2,
-                         presets.T3 != 0 ? presets.T3 : presetDefault.T3, 
+                         presets.T3 != 0 ? presets.T3 : presetDefault.T3,
                          presets.RESET != 0 ? presets.RESET : presetDefault.RESET);
-         }     
+         }
 
 
          bool IsInterleaved()
@@ -155,13 +155,13 @@ public:
 
          signed char QuantizeGratientOrg(LONG Di);
          inlinehint LONG QuantizeGratient(LONG Di)
-         { 
+         {
                  ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di));
-                 return *(_pquant + Di); 
+                 return *(_pquant + Di);
          }
 
          void InitQuantizationLUT();
-       
+
          LONG DecodeValue(LONG k, LONG limit, LONG qbpp);
          inlinehint void EncodeMappedValue(LONG k, LONG mappedError, LONG limit);
 
@@ -216,27 +216,27 @@ public:
          {
                LONG sign               = BitWiseSign(Qs);
                JlsContext& ctx = _contexts[ApplySign(Qs, sign)];
-               LONG k                  = ctx.GetGolomb();      
-               LONG Px                 = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign));    
+               LONG k                  = ctx.GetGolomb();
+               LONG Px                 = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign));
 
                LONG ErrVal;
                const Code& code                = decodingTables[k].Get(STRATEGY::PeekByte());
                if (code.GetLength() != 0)
                {
                        STRATEGY::Skip(code.GetLength());
-                       ErrVal = code.GetValue(); 
+                       ErrVal = code.GetValue();
                        ASSERT(ABS(ErrVal) < 65535);
                }
                else
                {
-                       ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp)); 
+                       ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp));
                        if (ABS(ErrVal) > 65535)
                                throw JlsException(InvalidCompressedData);
-               }       
+               }
                ErrVal = ErrVal ^ ((traits.NEAR == 0) ? ctx.GetErrorCorrection(k) : 0);
-               ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); 
+               ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET);
                ErrVal = ApplySign(ErrVal, sign);
-               return traits.ComputeReconstructedSample(Px, ErrVal); 
+               return traits.ComputeReconstructedSample(Px, ErrVal);
          }
 
 
@@ -245,7 +245,7 @@ public:
                LONG sign               = BitWiseSign(Qs);
                JlsContext& ctx = _contexts[ApplySign(Qs, sign)];
                LONG k                  = ctx.GetGolomb();
-               LONG Px                 = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign));      
+               LONG Px                 = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign));
 
                LONG ErrVal             = traits.ComputeErrVal(ApplySign(x - Px, sign));
 
@@ -270,16 +270,16 @@ public:
        size_t  DecodeScan(void* rawData, const JlsRect& size, BYTE **buf, size_t *buf_size, size_t offset, bool bCompare);
 
 protected:
-       // codec parameters 
+       // codec parameters
        TRAITS traits;
        JlsRect _rect;
        int _width;
-       LONG T1;        
+       LONG T1;
        LONG T2;
-       LONG T3; 
+       LONG T3;
 
        // compression context
-       JlsContext _contexts[365];      
+       JlsContext _contexts[365];
        CContextRunMode _contextRunmode[2];
        LONG _RUNindex;
        PIXEL* _previousLine; // previous line ptr
@@ -309,7 +309,7 @@ CTable InitTable(LONG k)
        CTable table;
        short nerr;
        for (nerr = 0; ; nerr++)
-       {               
+       {
                // Q is not used when k != 0
                LONG merrval = GetMappedErrVal(nerr);//, k, -1);
                OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval);
@@ -321,7 +321,7 @@ CTable InitTable(LONG k)
        }
 
        for (nerr = -1; ; nerr--)
-       {               
+       {
                // Q is not used when k != 0
                LONG merrval = GetMappedErrVal(nerr);//, k, -1);
                OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval);
@@ -364,7 +364,7 @@ inlinehint void JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
                if (highbits + 1 > 31)
                {
                        STRATEGY::AppendToBitStream(0, highbits / 2);
-                       highbits = highbits - highbits / 2;                                                                                                     
+                       highbits = highbits - highbits / 2;
                }
                STRATEGY::AppendToBitStream(1, highbits + 1);
                STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k);
@@ -374,11 +374,11 @@ inlinehint void JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
        if (limit - traits.qbpp > 31)
        {
                STRATEGY::AppendToBitStream(0, 31);
-               STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31);                       
+               STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31);
        }
        else
        {
-               STRATEGY::AppendToBitStream(1, limit - traits.qbpp);                    
+               STRATEGY::AppendToBitStream(1, limit - traits.qbpp);
        }
        STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 1), traits.qbpp);
 }
@@ -389,33 +389,33 @@ inlinehint void JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
 template<class TRAITS, class STRATEGY>
 void JlsCodec<TRAITS,STRATEGY>::InitQuantizationLUT()
 {
-       // for lossless mode with default parameters, we have precomputed te luts for bitcounts 8,10,12 and 16 
+       // for lossless mode with default parameters, we have precomputed te luts for bitcounts 8,10,12 and 16
        if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1)
        {
                JlsCustomParameters presets = ComputeDefault(traits.MAXVAL, traits.NEAR);
                if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3)
                {
-                       if (traits.bpp == 8) 
+                       if (traits.bpp == 8)
                        {
-                               _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ]; 
+                               _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ];
                                return;
                        }
-                       if (traits.bpp == 10) 
+                       if (traits.bpp == 10)
                        {
-                               _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ]; 
+                               _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ];
                                return;
-                       }                       
-                       if (traits.bpp == 12) 
+                       }
+                       if (traits.bpp == 12)
                        {
-                               _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ]; 
+                               _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ];
                                return;
-                       }                       
-                       if (traits.bpp == 16) 
+                       }
+                       if (traits.bpp == 16)
                        {
-                               _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ]; 
+                               _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ];
                                return;
-                       }                       
-               }       
+                       }
+               }
        }
 
        LONG RANGE = 1 << traits.bpp;
@@ -453,7 +453,7 @@ template<class TRAITS, class STRATEGY>
 LONG JlsCodec<TRAITS,STRATEGY>::DecodeRIError(CContextRunMode& ctx)
 {
        LONG k = ctx.GetGolomb();
-       LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp);     
+       LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp);
        LONG Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k);
        ctx.UpdateVariables(Errval, EMErrval);
        return Errval;
@@ -466,7 +466,7 @@ void JlsCodec<TRAITS,STRATEGY>::EncodeRIError(CContextRunMode& ctx, LONG Errval)
 {
        LONG k                  = ctx.GetGolomb();
        bool map                = ctx.ComputeMap(Errval, k);
-       LONG EMErrval   = 2 * ABS(Errval) - ctx._nRItype - map; 
+       LONG EMErrval   = 2 * ABS(Errval) - ctx._nRItype - map;
 
        ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k));
        EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1);
@@ -476,7 +476,7 @@ void JlsCodec<TRAITS,STRATEGY>::EncodeRIError(CContextRunMode& ctx, LONG Errval)
 
 template<class TRAITS, class STRATEGY>
 Triplet<OFTypename TRAITS::SAMPLE> JlsCodec<TRAITS,STRATEGY>::DecodeRIPixel(Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb)
-{ 
+{
        LONG Errval1 = DecodeRIError(_contextRunmode[0]);
        LONG Errval2 = DecodeRIError(_contextRunmode[0]);
        LONG Errval3 = DecodeRIError(_contextRunmode[0]);
@@ -513,18 +513,18 @@ Triplet<OFTypename TRAITS::SAMPLE> JlsCodec<TRAITS,STRATEGY>::EncodeRIPixel(Trip
 template<class TRAITS, class STRATEGY>
 void JlsCodec<TRAITS,STRATEGY>::EncodeRunPixels(LONG runLength, bool endOfLine)
 {
-       while (runLength >= LONG(1 << J[_RUNindex])) 
+       while (runLength >= LONG(1 << J[_RUNindex]))
        {
                STRATEGY::AppendOnesToBitStream(1);
                runLength = runLength - LONG(1 << J[_RUNindex]);
                IncrementRunIndex();
        }
 
-       if (endOfLine) 
+       if (endOfLine)
        {
-               if (runLength != 0) 
+               if (runLength != 0)
                {
-                       STRATEGY::AppendOnesToBitStream(1);     
+                       STRATEGY::AppendOnesToBitStream(1);
                }
        }
        else
@@ -556,7 +556,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, LONG
 
        if (index != cpixelMac)
        {
-               // incomplete run       
+               // incomplete run
                index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) : 0;
        }
 
@@ -566,7 +566,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, LONG
        for (LONG i = 0; i < index; ++i)
        {
                startPos[i] = Ra;
-       }       
+       }
 
        return index;
 }
@@ -582,7 +582,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DoRunMode(LONG index, EncoderStrategy*)
 
        LONG runLength = 0;
 
-       while (traits.IsNear(ptypeCurX[runLength],Ra)) 
+       while (traits.IsNear(ptypeCurX[runLength],Ra))
        {
                ptypeCurX[runLength] = Ra;
                runLength++;
@@ -629,14 +629,24 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*)
        LONG index = 0;
        LONG Rb = _previousLine[index-1];
        LONG Rd = _previousLine[index];
+    LONG RANGE_UPPER = 1 << traits.bpp;
+    LONG RANGE_LOWER = - RANGE_UPPER;
 
        while(index < _width)
-       {       
+       {
                LONG Ra = _currentLine[index -1];
                LONG Rc = Rb;
                Rb = Rd;
                Rd = _previousLine[index + 1];
 
+        // make sure that values are not out of range
+        if (  (Rd - Rb < RANGE_LOWER) || (Rd - Rb > RANGE_UPPER)
+           || (Rb - Rc < RANGE_LOWER) || (Rb - Rc > RANGE_UPPER)
+           || (Rc - Ra < RANGE_LOWER) || (Rc - Ra > RANGE_UPPER))
+        {
+            throw JlsException(InvalidCompressedData);
+        }
+
                LONG Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra));
 
                if (Qs != 0)
@@ -648,8 +658,8 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*)
                {
                        index += DoRunMode(index, (STRATEGY*)(NULL));
                        Rb = _previousLine[index-1];
-                       Rd = _previousLine[index];      
-               }                               
+                       Rd = _previousLine[index];
+               }
        }
 }
 
@@ -661,7 +671,7 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
 {
        LONG index = 0;
        while(index < _width)
-       {               
+       {
                Triplet<SAMPLE> Ra = _currentLine[index -1];
                Triplet<SAMPLE> Rc = _previousLine[index-1];
                Triplet<SAMPLE> Rb = _previousLine[index];
@@ -671,7 +681,7 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
                LONG Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2));
                LONG Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3));
 
-               
+
                if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0)
                {
                        index += DoRunMode(index, (STRATEGY*)(NULL));
@@ -684,19 +694,19 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
                        Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), (STRATEGY*)(NULL));
                        _currentLine[index] = Rx;
                        index++;
-               }       
+               }
        }
 }
 
 
-// DoScan: Encodes or decodes a scan. 
+// DoScan: Encodes or decodes a scan.
 // In ILV_SAMPLE mode, multiple components are handled in DoLine
 // In ILV_LINE mode, a call do DoLine is made for every component
-// In ILV_NONE mode, DoScan is called for each component 
+// In ILV_NONE mode, DoScan is called for each component
 
 template<class TRAITS, class STRATEGY>
 void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, size_t *size, size_t offset)
-{              
+{
        _width = Info().width;
 
        STRATEGY::Init(ptr, size, offset);
@@ -706,11 +716,11 @@ void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, size_t *size, size_t offset)
 
        OFVector<PIXEL> vectmp(2 * components * pixelstride);
        OFVector<LONG> rgRUNindex(components);
-       
+
        for (LONG line = 0; line < Info().height; ++line)
        {
-               _previousLine                   = &vectmp[1];   
-               _currentLine                    = &vectmp[1 + components * pixelstride];        
+               _previousLine                   = &vectmp[1];
+               _currentLine                    = &vectmp[1 + components * pixelstride];
                if ((line & 1) == 1)
                {
                        PIXEL *tmp = _previousLine;
@@ -724,17 +734,17 @@ void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, size_t *size, size_t offset)
                for (int component = 0; component < components; ++component)
                {
                        _RUNindex = rgRUNindex[component];
-               
+
                        // initialize edge pixels used for prediction
                        _previousLine[_width]   = _previousLine[_width - 1];
                        _currentLine[-1]                = _previousLine[0];
                        DoLine((PIXEL*) NULL); // dummy arg for overload resolution
-       
+
                        rgRUNindex[component] = _RUNindex;
                        _previousLine += pixelstride;
                        _currentLine += pixelstride;
                }
-               
+
                if (_rect.Y <= line && line < _rect.Y + _rect.Height)
                {
                        STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X - (components * pixelstride), pixelstride);
@@ -754,7 +764,7 @@ ProcessLine* JlsCodec<TRAITS,STRATEGY>::CreateProcess(void* pvoidOut)
                return new PostProcesSingleComponent(pvoidOut, Info(), sizeof(typename TRAITS::PIXEL));
 
        if (Info().colorTransform == 0)
-               return new ProcessTransformed<TransformNone<OFTypename TRAITS::SAMPLE> >(pvoidOut, Info(), TransformNone<SAMPLE>()); 
+               return new ProcessTransformed<TransformNone<OFTypename TRAITS::SAMPLE> >(pvoidOut, Info(), TransformNone<SAMPLE>());
 
        if (Info().bitspersample == sizeof(SAMPLE)*8)
        {
@@ -765,7 +775,7 @@ ProcessLine* JlsCodec<TRAITS,STRATEGY>::CreateProcess(void* pvoidOut)
                        case COLORXFORM_HP3 : return new ProcessTransformed<TransformHp3<SAMPLE> >(pvoidOut, Info(), TransformHp3<SAMPLE>()); break;
                        default: throw JlsException(UnsupportedColorTransform);
                }
-       } 
+       }
        else if (Info().bitspersample > 8)
        {
                int shift = 16 - Info().bitspersample;
@@ -796,7 +806,7 @@ size_t JlsCodec<TRAITS,STRATEGY>::EncodeScan(const void* rawData, BYTE **ptr, si
        }
 
        DoScan(ptr, size, offset);
-       
+
        return  STRATEGY::GetLength();
 
 }
@@ -827,7 +837,7 @@ size_t JlsCodec<TRAITS,STRATEGY>::DecodeScan(void* rawData, const JlsRect& rect,
        _rect = rect;
 
        DoScan(ptr, size, offset + readBytes);
-       
+
        return STRATEGY::GetCurBytePos() - (*ptr + offset);
 }
 
index 1e7f123bce4349a60672834ba61c6b4fc9e004f4..de71e0e54d52bbf771709d0c25359d09329ab152 100644 (file)
@@ -1,6 +1,6 @@
-// 
-// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 
-// 
+//
+// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
+//
 #ifndef CHARLS_STREAMS
 #define CHARLS_STREAMS
 
@@ -10,7 +10,7 @@
 
 
 
-// This file defines JPEG-LS streams: The header and the actual pixel data. Header markers have fixed length, the pixeldata not. 
+// This file defines JPEG-LS streams: The header and the actual pixel data. Header markers have fixed length, the pixeldata not.
 
 
 
@@ -18,112 +18,108 @@ class JpegSegment;
 
 enum JPEGLS_ColorXForm
 {
-       // default (RGB)
-       COLORXFORM_NONE = 0,    
+    // default (RGB)
+    COLORXFORM_NONE = 0,
 
-       // Color transforms as defined by HP
-       COLORXFORM_HP1,
-       COLORXFORM_HP2,
-       COLORXFORM_HP3,
+    // Color transforms as defined by HP
+    COLORXFORM_HP1,
+    COLORXFORM_HP2,
+    COLORXFORM_HP3,
 
-       // Defined by HP but not supported by CharLS
-       COLORXFORM_RGB_AS_YUV_LOSSY,
-       COLORXFORM_MATRIX
+    // Defined by HP but not supported by CharLS
+    COLORXFORM_RGB_AS_YUV_LOSSY,
+    COLORXFORM_MATRIX
 };
-       
+
 //
 // JLSOutputStream: minimal implementation to write JPEG header streams
 //
 class JLSOutputStream
 {
-       friend class JpegMarkerSegment;
-       friend class JpegImageDataSegment;
+    friend class JpegMarkerSegment;
+    friend class JpegImageDataSegment;
 
 public:
-       JLSOutputStream();
-       virtual ~JLSOutputStream();
+    JLSOutputStream();
+    virtual ~JLSOutputStream();
 
-       void Init(Size size, LONG bitsPerSample, LONG ccomp);
-       void AddScan(const void* compareData, const JlsParameters* pparams);
-       void AddLSE(const JlsCustomParameters* pcustom);
-       void AddColorTransform(int i);
-       size_t GetBytesWritten()
-               { return _cbytesWritten; }
+    void Init(Size size, LONG bitsPerSample, LONG ccomp);
+    void AddScan(const void* compareData, const JlsParameters* pparams);
+    void AddLSE(const JlsCustomParameters* pcustom);
+    void AddColorTransform(int i);
+    size_t GetBytesWritten()
+        { return _cbytesWritten; }
 
-       size_t Write(BYTE **ptr, size_t *size, size_t offset);
+    size_t Write(BYTE **ptr, size_t *size, size_t offset);
 
-       BYTE **get_pos() { return _position; }
+    BYTE **get_pos() { return _position; }
 
-       size_t *get_size() { return _size; }
+    size_t *get_size() { return _size; }
 
-       size_t get_offset() { return _current_offset; }
+    size_t get_offset() { return _current_offset; }
 
-       void EnableCompare(bool bCompare) 
-       { _bCompare = bCompare; }
+    void EnableCompare(bool bCompare)
+    { _bCompare = bCompare; }
 private:
-       void WriteByte(BYTE val)
-       { 
-               ASSERT(!_bCompare || (*_position)[_current_offset] == val);
-               
-               if (_current_offset == *_size) {
-                       *_position = re_alloc(*_position, _size);
-               }
-
-               (*_position)[_current_offset++] = val;
-
-               _cbytesWritten++;
-       }
-
-       void WriteBytes(const OFVector<BYTE>& rgbyte)
-       {
-               for (size_t i = 0; i < rgbyte.size(); ++i)
-               {
-                       WriteByte(rgbyte[i]);
-               }               
-       }
-
-       void WriteWord(USHORT val)
-       {
-               WriteByte(BYTE(val / 0x100));
-               WriteByte(BYTE(val % 0x100));
-       }
-
-       void seek(size_t n)
-       {
-               _cbytesWritten += n;
-               _current_offset += n;
-       }
-
-       bool _bCompare;
+    void WriteByte(BYTE val)
+    {
+        ASSERT(!_bCompare || (*_position)[_current_offset] == val);
+
+        if (_current_offset == *_size) {
+            *_position = re_alloc(*_position, _size);
+        }
+
+        (*_position)[_current_offset++] = val;
+
+        _cbytesWritten++;
+    }
+
+    void WriteBytes(const OFVector<BYTE>& rgbyte)
+    {
+        for (size_t i = 0; i < rgbyte.size(); ++i)
+        {
+            WriteByte(rgbyte[i]);
+        }
+    }
+
+    void WriteWord(USHORT val)
+    {
+        WriteByte(BYTE(val / 0x100));
+        WriteByte(BYTE(val % 0x100));
+    }
+
+    void seek(size_t n)
+    {
+        _cbytesWritten += n;
+        _current_offset += n;
+    }
+
+    bool _bCompare;
 
 private:
-       static BYTE *re_alloc(BYTE *old_ptr, size_t *old_size)
-       {
-               size_t new_size = *old_size * 2;
-#ifdef HAVE_STD__NOTHROW
-               BYTE *new_ptr = new BYTE[new_size];
-#else
-               BYTE *new_ptr = new BYTE[new_size];
-#endif
-               if (new_ptr == NULL) {
-                       throw alloc_fail();
-               }
+    static BYTE *re_alloc(BYTE *old_ptr, size_t *old_size)
+    {
+        size_t new_size = *old_size * 2;
+        BYTE *new_ptr = new(std::nothrow) BYTE[new_size];
+        if (new_ptr == NULL) {
+            throw alloc_fail();
+        }
 
-               OFBitmanipTemplate<BYTE>::copyMem(old_ptr, new_ptr, *old_size);
+        OFBitmanipTemplate<BYTE>::copyMem(old_ptr, new_ptr, *old_size);
 
-               delete[] old_ptr;
+        delete[] old_ptr;
 
-               *old_size = new_size;
+        *old_size = new_size;
 
-               return new_ptr;
-       }
+        return new_ptr;
+    }
 
-       BYTE **_position;
-       size_t *_size;
-       size_t _current_offset;
-       size_t _cbytesWritten;
-       LONG _icompLast;
-       OFVector<JpegSegment*> _segments;
+    BYTE **_position;
+    size_t *_size;
+    size_t _current_offset;
+    size_t _cbytesWritten;
+    LONG _icompLast;
+    OFVector<JpegSegment*> _segments;
 };
 
 
@@ -133,51 +129,51 @@ private:
 class JLSInputStream
 {
 public:
-       JLSInputStream(const BYTE* pdata, size_t cbyteLength);
+    JLSInputStream(const BYTE* pdata, size_t cbyteLength);
+
+    size_t GetBytesRead()
+        { return _cbyteOffset; }
 
-       size_t GetBytesRead()
-               { return _cbyteOffset; }
+    const JlsParameters& GetMetadata() const
+        { return _info; }
 
-       const JlsParameters& GetMetadata() const
-               { return _info; } 
+    const JlsCustomParameters& GetCustomPreset() const
+    { return _info.custom; }
 
-       const JlsCustomParameters& GetCustomPreset() const
-       { return _info.custom; } 
+    void Read(void* pvoid, size_t cbyteAvailable);
+    void ReadHeader();
 
-       void Read(void* pvoid, size_t cbyteAvailable);
-       void ReadHeader();
-       
-       void EnableCompare(bool bCompare)
-               { _bCompare = bCompare; }
+    void EnableCompare(bool bCompare)
+        { _bCompare = bCompare; }
 
-       void SetInfo(JlsParameters* info) { _info = *info; }
+    void SetInfo(JlsParameters* info) { _info = *info; }
 
-       void SetRect(JlsRect rect) { _rect = rect; }
+    void SetRect(JlsRect rect) { _rect = rect; }
 
 private:
-       void ReadPixels(void* pvoid, size_t cbyteAvailable);
-       void ReadScan(void*);   
-       void ReadStartOfScan();
-       void ReadPresetParameters();
-       void ReadComment();
-       void ReadStartOfFrame();
-       BYTE ReadByte();
-       int ReadWord();
-       void ReadNBytes(OFVector<char>& dst, int byteCount);
-
-       // JFIF
-       void ReadJfif();
-       // Color Transform Application Markers & Code Stream (HP extension)
-       void ReadColorSpace();
-       void ReadColorXForm();
-       
+    void ReadPixels(void* pvoid, size_t cbyteAvailable);
+    void ReadScan(void*);
+    void ReadStartOfScan();
+    void ReadPresetParameters();
+    void ReadComment();
+    void ReadStartOfFrame();
+    BYTE ReadByte();
+    int ReadWord();
+    void ReadNBytes(OFVector<char>& dst, int byteCount);
+
+    // JFIF
+    void ReadJfif();
+    // Color Transform Application Markers & Code Stream (HP extension)
+    void ReadColorSpace();
+    void ReadColorXForm();
+
 private:
-       const BYTE* _pdata;
-       size_t _cbyteOffset;
-       size_t _cbyteLength;
-       bool _bCompare;
-       JlsParameters _info;
-       JlsRect _rect;
+    const BYTE* _pdata;
+    size_t _cbyteOffset;
+    size_t _cbyteLength;
+    bool _bCompare;
+    JlsParameters _info;
+    JlsRect _rect;
 };
 
 
index ca549afdb91282f7e99dacc08d81a7baee66394b..27f576dbc90fde7182519b4fd0563d280e94ce21 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2024, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -76,6 +76,24 @@ OFBool DJLSDecoderBase::canChangeCoding(
 }
 
 
+Uint16 DJLSDecoderBase::decodedBitsAllocated(
+    Uint16 /* bitsAllocated */,
+    Uint16 bitsStored) const
+{
+  // this codec does not support images with less than 2 bits per sample
+  if (bitsStored < 2) return 0;
+
+  // for images with 2..8 bits per sample, BitsAllocated will be 8
+  if (bitsStored <= 8) return 8;
+
+  // for images with 9..16 bits per sample, BitsAllocated will be 16
+  if (bitsStored <= 16) return 16;
+
+  // this codec does not support images with more than 16 bits per sample
+  return 0;
+}
+
+
 OFCondition DJLSDecoderBase::decode(
     const DcmRepresentationParameter * /* fromRepParam */,
     DcmPixelSequence * pixSeq,
@@ -186,7 +204,7 @@ OFCondition DJLSDecoderBase::decode(
   {
       DCMJPLS_DEBUG("JPEG-LS decoder processes frame " << (currentFrame+1));
 
-      result = decodeFrame(pixSeq, djcp, dataset, currentFrame, currentItem, pixeldata8, frameSize,
+      result = decodeFrameNoSwap(pixSeq, djcp, dataset, currentFrame, currentItem, pixeldata8, frameSize,
           imageFrames, imageColumns, imageRows, imageSamplesPerPixel, bytesPerSample);
 
       // check if we should enforce "one fragment per frame" while
@@ -215,6 +233,15 @@ OFCondition DJLSDecoderBase::decode(
     result = ((DcmItem *)dataset)->putAndInsertString(DCM_NumberOfFrames, numBuf);
   }
 
+  if (result.good())
+  {
+    // decompression is complete, finally adjust byte order if necessary
+    if (bytesPerSample == 1) // we're writing bytes into words
+    {
+      result = swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, pixeldata16, OFstatic_cast(Uint32, totalSize), sizeof(Uint16));
+    }
+  }
+
   if (result.good() && (dataset->ident() == EVR_dataset))
   {
     DcmItem *ditem = OFreinterpret_cast(DcmItem*, dataset);
@@ -315,7 +342,7 @@ OFCondition DJLSDecoderBase::decodeFrame(
   return result;
 }
 
-OFCondition DJLSDecoderBase::decodeFrame(
+OFCondition DJLSDecoderBase::decodeFrameNoSwap(
     DcmPixelSequence * fromPixSeq,
     const DJLSCodecParameter *cp,
     DcmItem *dataset,
@@ -472,16 +499,6 @@ OFCondition DJLSDecoderBase::decodeFrame(
         }
       }
 
-      if (result.good())
-      {
-          // decompression is complete, finally adjust byte order if necessary
-          if (bytesPerSample == 1) // we're writing bytes into words
-          {
-              result = swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, buffer,
-                      bufSize, sizeof(Uint16));
-          }
-      }
-
       // update planar configuration if we are decoding a color image
       if (result.good() && (imageSamplesPerPixel > 1))
       {
@@ -493,6 +510,35 @@ OFCondition DJLSDecoderBase::decodeFrame(
   return result;
 }
 
+OFCondition DJLSDecoderBase::decodeFrame(
+    DcmPixelSequence * fromPixSeq,
+    const DJLSCodecParameter *cp,
+    DcmItem *dataset,
+    Uint32 frameNo,
+    Uint32& currentItem,
+    void * buffer,
+    Uint32 bufSize,
+    Sint32 imageFrames,
+    Uint16 imageColumns,
+    Uint16 imageRows,
+    Uint16 imageSamplesPerPixel,
+    Uint16 bytesPerSample)
+{
+    OFCondition result = decodeFrameNoSwap(fromPixSeq, cp, dataset, frameNo, currentItem, buffer, bufSize, imageFrames, imageColumns, imageRows, imageSamplesPerPixel, bytesPerSample);
+    if (result.good())
+    {
+        // decompression is complete, finally adjust byte order if necessary
+        if (bytesPerSample == 1) // we're writing bytes into words
+        {
+            if ((gLocalByteOrder == EBO_BigEndian) && (bufSize & 1))
+            {
+              DCMJPLS_WARN("Size of frame buffer is odd, cannot correct byte order for last pixel value");
+            }
+            result = swapIfNecessary(gLocalByteOrder, EBO_LittleEndian, buffer, bufSize, sizeof(Uint16));
+        }
+    }
+    return result;
+}
 
 OFCondition DJLSDecoderBase::encode(
     const Uint16 * /* pixelData */,
index d6acbf052edcb17961121c448034dfed2ac40a2f..b6ea54176bb4fe81d8b704477fd8ce420b52181e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2007-2024, OFFIS e.V.
+ *  Copyright (C) 2007-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "intrface.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* for O_RDONLY */
-#endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* required for sys/stat.h */
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat, fstat */
-#endif
 END_EXTERN_C
 
 
@@ -100,6 +94,14 @@ OFBool DJLSEncoderBase::canChangeCoding(
 }
 
 
+Uint16 DJLSEncoderBase::decodedBitsAllocated(
+    Uint16 /* bitsAllocated */,
+    Uint16 /* bitsStored */) const
+{
+  return 0;
+}
+
+
 OFCondition DJLSEncoderBase::decode(
     const DcmRepresentationParameter * /* fromRepParam */,
     DcmPixelSequence * /* pixSeq */,
@@ -666,7 +668,7 @@ OFCondition DJLSEncoderBase::compressRawFrame(
   jls_params.width = width;
   jls_params.allowedlossyerror = 0; // must be zero for raw mode
   jls_params.outputBgr = false;
-  // No idea what this one does, but I don't think DICOM says anything about it
+  // color transformation is a non-standard HP/JPEG-LS extension
   jls_params.colorTransform = 0;
   // Unset: jls_params.jfif (thumbnail, dpi)
 
@@ -1015,12 +1017,17 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
     case EPR_Sint8:
       {
         // image representation is 8 bit signed or unsigned
+        Uint8 mask = 0xFF >> (8-depth);
         if (samplesPerPixel == 1)
         {
           const Uint8 *yv = OFreinterpret_cast(const Uint8 *, planes[0]) + framesize * frame;
           buffer_size = framesize;
           buffer = new Uint8[buffer_size];
-          memcpy(buffer, yv, framesize);
+          for (size_t i=0; i < framesize; ++i)
+          {
+              buffer[i] = *yv & mask;
+              yv++;
+          }
         }
         else
         {
@@ -1036,9 +1043,9 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
           {
             for (int col=width; col; --col)
             {
-              buffer[i++] = *rv;
-              buffer[i++] = *gv;
-              buffer[i++] = *bv;
+              buffer[i++] = *rv & mask;
+              buffer[i++] = *gv & mask;
+              buffer[i++] = *bv & mask;
 
               rv++;
               gv++;
@@ -1052,12 +1059,23 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
     case EPR_Sint16:
       {
         // image representation is 16 bit signed or unsigned
+        Uint16 mask = 0xFFFF >> (16-depth);
         if (samplesPerPixel == 1)
         {
           const Uint16 *yv = OFreinterpret_cast(const Uint16 *, planes[0]) + framesize * frame;
-          buffer_size = framesize*sizeof(Uint16);
-          buffer = new Uint8[buffer_size];
-          memcpy(buffer, yv, buffer_size);
+
+          buffer_size = framesize;
+          Uint16 *buffer16 = new Uint16[buffer_size];
+          buffer = OFreinterpret_cast(Uint8 *, buffer16);
+
+          // Convert to byte count
+          buffer_size *= 2;
+
+          for (size_t i=0; i < framesize; ++i)
+          {
+              buffer16[i] = *yv & mask;
+              yv++;
+          }
         }
         else
         {
@@ -1077,9 +1095,9 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
           {
             for (int col=width; col; --col)
             {
-              buffer16[i++] = *rv;
-              buffer16[i++] = *gv;
-              buffer16[i++] = *bv;
+              buffer16[i++] = *rv & mask;
+              buffer16[i++] = *gv & mask;
+              buffer16[i++] = *bv & mask;
 
               rv++;
               gv++;
@@ -1104,7 +1122,7 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
   jls_params.allowedlossyerror = nearLosslessDeviation;
   jls_params.outputBgr = false;
   jls_params.bitspersample = depth;
-  // No idea what this one does, but I don't think DICOM says anything about it
+  // color transformation is a non-standard HP/JPEG-LS extension
   jls_params.colorTransform = 0;
 
   // This was already checked for a sane value above
@@ -1168,7 +1186,7 @@ OFCondition DJLSEncoderBase::compressCookedFrame(
   {
     // 'compressed_buffer_size' now contains the size of the compressed data in buffer
     compressedSize = OFstatic_cast(unsigned long, bytesWritten);
-    fixPaddingIfNecessary(OFstatic_cast(Uint8 *, buffer), compressed_buffer_size, compressedSize, djcp->getUseFFbitstreamPadding());
+    fixPaddingIfNecessary(OFstatic_cast(Uint8 *, compressed_buffer), compressed_buffer_size, compressedSize, djcp->getUseFFbitstreamPadding());
     result = pixelSequence->storeCompressedFrame(offsetList, compressed_buffer, compressedSize, fragmentSize);
   }
 
index 8ac501c4032923ca55fd3a8ab4df83741fd193f3..f771154cff1b286aa7558bdbbbe04eb2003f2bc8 100644 (file)
@@ -26,10 +26,10 @@ if(WITH_OPENSSL)
 endif()
 
 # make sure executables are linked to the corresponding libraries
-foreach(PROGRAM dcmrecv dcmsend echoscu findscu getscu movescu storescp storescu termscu)
-  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmnet dcmdata oflog ofstd)
+foreach(PROGRAM dcmsend termscu)
+  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmnet)
 endforeach()
-foreach(PROGRAM dcmrecv echoscu findscu storescp storescu getscu)
+foreach(PROGRAM dcmrecv echoscu findscu storescp storescu getscu movescu)
   DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmtls)
 endforeach()
 
index d8f4d2f14658db848337b32ef342f91baddccf65..cb3941e41d2bb6553e932ddfcbcaf5b8e67424e9 100644 (file)
@@ -678,7 +678,12 @@ movescu.o: movescu.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcmetinf.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdicent.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcostrmz.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcostrma.h
+ ../../dcmdata/include/dcmtk/dcmdata/dcostrma.h \
+ ../../dcmtls/include/dcmtk/dcmtls/tlsopt.h \
+ ../../dcmtls/include/dcmtk/dcmtls/tlslayer.h \
+ ../include/dcmtk/dcmnet/dcmlayer.h \
+ ../../dcmtls/include/dcmtk/dcmtls/tlsdefin.h \
+ ../../dcmtls/include/dcmtk/dcmtls/tlsciphr.h
 storescp.o: storescp.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
index 4818e031bfa990bc7a4edda9d6540db0dff3ce22..36700c15e24c6ed9d80b803361e2916a12b8d59d 100644 (file)
@@ -57,7 +57,7 @@ findscu: findscu.o
        $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(DCMTLSLIBS) $(OPENSSLLIBS) $(LIBS)
 
 movescu: movescu.o
-       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
+       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(DCMTLSLIBS) $(OPENSSLLIBS) $(LIBS)
 
 termscu: termscu.o
        $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
index 6838fdd62bdfebf7387efc73f62f9cfc45528453..4934a2ec6336969ff39d5171b1ef35c7614a35ef 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2013-2024, OFFIS e.V.
+ *  Copyright (C) 2013-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -108,6 +108,11 @@ int main(int argc, char *argv[])
       cmd.addOption("--verbose-pc",            "+v",      "show presentation contexts in verbose mode");
 
     cmd.addGroup("network options:");
+      cmd.addSubGroup("IP protocol version:");
+        cmd.addOption("--ipv4",                "-i4",     "use IPv4 only (default)");
+        cmd.addOption("--ipv6",                "-i6",     "use IPv6 only");
+        cmd.addOption("--ip-auto",             "-i0",     "use IPv6/IPv4 dual stack");
+
       cmd.addSubGroup("association negotiation profile from configuration file:");
         cmd.addOption("--config-file",         "-xf",  2, "[f]ilename, [p]rofile: string",
                                                           "use profile p from configuration file f");
@@ -177,7 +182,7 @@ int main(int argc, char *argv[])
                 return EXITCODE_NO_ERROR;
             }
 
-            // check if the command line contains the --list-profiles option
+            /* check if the command line contains the --list-profiles option */
             if (tlsOptions.listOfProfilesRequested(cmd))
             {
                 tlsOptions.printSupportedTLSProfiles(app, COUT);
@@ -195,6 +200,17 @@ int main(int argc, char *argv[])
         }
 
         /* network options */
+
+        /* set the IP protocol version */
+        cmd.beginOptionBlock();
+        if (cmd.findOption("--ipv4"))
+            dcmIncomingProtocolFamily.set(ASC_AF_INET);
+        if (cmd.findOption("--ipv6"))
+            dcmIncomingProtocolFamily.set(ASC_AF_INET6);
+        if (cmd.findOption("--ip-auto"))
+            dcmIncomingProtocolFamily.set(ASC_AF_UNSPEC);
+        cmd.endOptionBlock();
+
         if (cmd.findOption("--config-file"))
         {
             app.checkValue(cmd.getValue(opt_configFile));
index c79869b25d3b43398b96d9d25b0bbe0490285a2d..4bdb425171282e8a84f04a9d8bf65c841fc9ea6c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -89,6 +89,7 @@ static const char* transferSyntaxes[] = {
       UID_JPEGProcess14SV1TransferSyntax,
       UID_RLELosslessTransferSyntax,
       UID_DeflatedExplicitVRLittleEndianTransferSyntax,
+      UID_DeflatedImageFrameCompressionTransferSyntax,
       UID_JPEGLSLosslessTransferSyntax,
       UID_JPEGLSLossyTransferSyntax,
       UID_JPEG2000LosslessOnlyTransferSyntax,
index bde6ec28f44d7da008daf10406c44ef347bee7e1..fe37c8d9c441a2f0a665970026a4059b8a1371d6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -36,6 +36,7 @@
 #include "dcmtk/dcmdata/dcdicent.h"
 #include "dcmtk/dcmdata/dcostrmz.h"   /* for dcmZlibCompressionLevel */
 #include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/dcmtls/tlsopt.h"      /* for DcmTLSOptions */
 
 #ifdef WITH_ZLIB
 #include <zlib.h>     /* for zlibVersion() */
@@ -63,7 +64,7 @@ static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
 #define EXITCODE_CANNOT_CLOSE_ASSOCIATION       67
 #define EXITCODE_CMOVE_WARNING                  68
 #define EXITCODE_CMOVE_ERROR                    69
-
+#define EXITCODE_CANNOT_CREATE_TLS_LAYER        70
 
 typedef enum {
      QMPatientRoot = 0,
@@ -203,7 +204,7 @@ addOverrideKey(OFConsoleApplication& app, const char *s)
     }
 }
 
-static OFCondition cmove(T_ASC_Association *assoc, const char *fname);
+static OFCondition cmove(T_ASC_Association *assoc, const char *fname, OFBool secureConnection);
 
 static OFCondition
 addPresentationContext(T_ASC_Parameters *params,
@@ -224,6 +225,7 @@ main(int argc, char *argv[])
   const char *opt_peerTitle = PEERAPPLICATIONTITLE;
   const char *opt_ourTitle = APPLICATIONTITLE;
   OFList<OFString> fileNameList;
+  DcmTLSOptions tlsOptions(NET_ACCEPTORREQUESTOR);
 
   OFStandard::initializeNetwork();
 
@@ -244,6 +246,10 @@ main(int argc, char *argv[])
    OFLog::addOptions(cmd);
 
   cmd.addGroup("network options:");
+    cmd.addSubGroup("IP protocol version:");
+      cmd.addOption("--ipv4",                "-i4",     "use IPv4 only (default)");
+      cmd.addOption("--ipv6",                "-i6",     "use IPv6 only");
+      cmd.addOption("--ip-auto",             "-i0",     "use IPv6/IPv4 dual stack");
     cmd.addSubGroup("override matching keys:");
       cmd.addOption("--key",                 "-k",   1, "[k]ey: gggg,eeee=\"str\" or dict. name=\"str\"",
                                                         "override matching key");
@@ -335,6 +341,10 @@ main(int argc, char *argv[])
       cmd.addOption("--cancel",                      1, "[n]umber: integer",
                                                         "cancel after n responses (default: never)");
       cmd.addOption("--uid-padding",         "-up",     "silently correct space-padded UIDs");
+
+  // add TLS specific command line options if (and only if) we are compiling with OpenSSL
+  tlsOptions.addTLSCommandlineOptions(cmd);
+
   cmd.addGroup("output options:");
     cmd.addSubGroup("general:");
       cmd.addOption("--output-directory",    "-od",  1, "[d]irectory: string (default: \".\")", "write received objects to existing directory d");
@@ -383,7 +393,7 @@ main(int argc, char *argv[])
         {
           app.printHeader(OFTrue /*print host identifier*/);
           COUT << OFendl << "External libraries used:";
-#if !defined(WITH_ZLIB) && !defined(WITH_TCPWRAPPER)
+#if !defined(WITH_ZLIB) && !defined(WITH_TCPWRAPPER) && !defined(WITH_OPENSSL)
           COUT << " none" << OFendl;
 #else
           COUT << OFendl;
@@ -394,10 +404,26 @@ main(int argc, char *argv[])
 #ifdef WITH_TCPWRAPPER
           COUT << "- LIBWRAP" << OFendl;
 #endif
+          // print OpenSSL version if (and only if) we are compiling with OpenSSL
+          tlsOptions.printLibraryVersion();
           return EXITCODE_NO_ERROR;
         }
       }
 
+      // check if the command line contains the --list-ciphers option
+      if (tlsOptions.listOfCiphersRequested(cmd))
+      {
+          tlsOptions.printSupportedCiphersuites(app, COUT);
+          return EXITCODE_NO_ERROR;
+      }
+
+      // check if the command line contains the --list-profiles option
+      if (tlsOptions.listOfProfilesRequested(cmd))
+      {
+          tlsOptions.printSupportedTLSProfiles(app, COUT);
+          return EXITCODE_NO_ERROR;
+      }
+
       /* command line parameters */
 
       cmd.getParam(1, opt_peer);
@@ -470,6 +496,13 @@ main(int argc, char *argv[])
 #endif
       cmd.endOptionBlock();
 
+      // set the IP protocol version
+      cmd.beginOptionBlock();
+      if (cmd.findOption("--ipv4")) dcmIncomingProtocolFamily.set(ASC_AF_INET);
+      if (cmd.findOption("--ipv6")) dcmIncomingProtocolFamily.set(ASC_AF_INET6);
+      if (cmd.findOption("--ip-auto")) dcmIncomingProtocolFamily.set(ASC_AF_UNSPEC);
+      cmd.endOptionBlock();
+
 #ifdef WITH_TCPWRAPPER
       cmd.beginOptionBlock();
       if (cmd.findOption("--access-full")) dcmTCPWrapperDaemonName.set(NULL);
@@ -517,6 +550,9 @@ main(int argc, char *argv[])
       if (cmd.findOption("--cancel"))  app.checkValue(cmd.getValueAndCheckMin(opt_cancelAfterNResponses, 0));
       if (cmd.findOption("--uid-padding")) opt_correctUIDPadding = OFTrue;
 
+      // evaluate (most of) the TLS command line options (if we are compiling with OpenSSL)
+      tlsOptions.parseArguments(app, cmd);
+
       if (cmd.findOption("--output-directory"))
       {
         app.checkDependence("--output-directory", "--port", opt_retrievePort > 0);
@@ -787,9 +823,21 @@ main(int argc, char *argv[])
     }
     ASC_setAPTitles(params, opt_ourTitle, opt_peerTitle, NULL);
 
+    // use the same network protocol family for incoming and outgoing connections
+    ASC_setProtocolFamily(params, dcmIncomingProtocolFamily.get());
+
     OFStandard::snprintf(peerHost, sizeof(peerHost), "%s:%d", opt_peer, OFstatic_cast(int, opt_port));
     ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost);
 
+    OFBool secureConnection = tlsOptions.secureConnectionRequested();
+
+    /* create a secure transport layer if requested and OpenSSL is available */
+    cond = tlsOptions.createTransportLayer(net, params, app, cmd);
+    if (cond.bad()) {
+      OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
+      return EXITCODE_CANNOT_CREATE_TLS_LAYER;
+    }
+
     /*
      * We also add a presentation context for the corresponding
      * find sop class.
@@ -838,13 +886,13 @@ main(int argc, char *argv[])
     if (fileNameList.empty())
     {
       /* no files provided on command line */
-      cond = cmove(assoc, NULL);
+      cond = cmove(assoc, NULL, secureConnection);
     } else {
       OFListIterator(OFString) iter = fileNameList.begin();
       OFListIterator(OFString) enditer = fileNameList.end();
       while ((iter != enditer) && cond.good())
       {
-          cond = cmove(assoc, (*iter).c_str());
+          cond = cmove(assoc, (*iter).c_str(), secureConnection);
           ++iter;
       }
     }
@@ -909,6 +957,12 @@ main(int argc, char *argv[])
 
     OFStandard::shutdownNetwork();
 
+    cond = tlsOptions.writeRandomSeed();
+    if (cond.bad()) {
+        // failure to write back the random seed is a warning, not an error
+        OFLOG_WARN(movescuLogger, DimseCondition::dump(temp_str, cond));
+    }
+
     return cmove_status_code;
 }
 
@@ -989,7 +1043,7 @@ addPresentationContext(T_ASC_Parameters *params,
 }
 
 static OFCondition
-acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc)
+acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc, OFBool secureConnection)
 {
     const char *knownAbstractSyntaxes[] = {
         UID_VerificationSOPClass
@@ -997,11 +1051,11 @@ acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc)
     const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 10
                                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 20
                                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 30
-                                       NULL, NULL, NULL, NULL, NULL };                               // +5
+                                       NULL, NULL, NULL, NULL, NULL, NULL };                         // +6
     int numTransferSyntaxes;
     OFString temp_str;
 
-    OFCondition cond = ASC_receiveAssociation(aNet, assoc, opt_maxPDU);
+    OFCondition cond = ASC_receiveAssociation(aNet, assoc, opt_maxPDU, NULL, NULL, secureConnection);
     if (cond.good())
     {
       OFLOG_INFO(movescuLogger, "Sub-Association Received");
@@ -1210,18 +1264,19 @@ acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc)
             transferSyntaxes[27] = UID_JPEGXLLosslessTransferSyntax;
             transferSyntaxes[28] = UID_JPEGXLJPEGRecompressionTransferSyntax;
             transferSyntaxes[29] = UID_JPEGXLTransferSyntax;
-            transferSyntaxes[30] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
-            transferSyntaxes[31] = UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax;
+            transferSyntaxes[30] = UID_DeflatedImageFrameCompressionTransferSyntax;
+            transferSyntaxes[31] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
+            transferSyntaxes[32] = UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax;
             if (gLocalByteOrder == EBO_LittleEndian)
             {
-              transferSyntaxes[32] = UID_LittleEndianExplicitTransferSyntax;
-              transferSyntaxes[33] = UID_BigEndianExplicitTransferSyntax;
-            } else {
-              transferSyntaxes[32] = UID_BigEndianExplicitTransferSyntax;
               transferSyntaxes[33] = UID_LittleEndianExplicitTransferSyntax;
+              transferSyntaxes[34] = UID_BigEndianExplicitTransferSyntax;
+            } else {
+              transferSyntaxes[33] = UID_BigEndianExplicitTransferSyntax;
+              transferSyntaxes[34] = UID_LittleEndianExplicitTransferSyntax;
             }
-            transferSyntaxes[34] = UID_LittleEndianImplicitTransferSyntax;
-            numTransferSyntaxes = 35;
+            transferSyntaxes[35] = UID_LittleEndianImplicitTransferSyntax;
+            numTransferSyntaxes = 36;
           } else {
             /* We prefer explicit transfer syntaxes.
              * If we are running on a Little Endian machine we prefer
@@ -1570,15 +1625,19 @@ subOpSCP(T_ASC_Association **subAssoc)
 }
 
 static void
-subOpCallback(void * /*subOpCallbackData*/ ,
+subOpCallback(void *subOpCallbackData,
         T_ASC_Network *aNet, T_ASC_Association **subAssoc)
 {
-
     if (aNet == NULL) return;   /* help no net ! */
 
+    OFBool secureConnection = OFFalse;
+    if (subOpCallbackData) {
+        secureConnection = * OFreinterpret_cast(OFBool *, subOpCallbackData);
+    }
+
     if (*subAssoc == NULL) {
         /* negotiate association */
-        acceptSubAssoc(aNet, subAssoc);
+        acceptSubAssoc(aNet, subAssoc, secureConnection);
     } else {
         /* be a service class provider */
         subOpSCP(subAssoc);
@@ -1637,7 +1696,7 @@ substituteOverrideKeys(DcmDataset *dset)
 
 
 static  OFCondition
-moveSCU(T_ASC_Association *assoc, const char *fname)
+moveSCU(T_ASC_Association *assoc, const char *fname, OFBool secureConnection)
 {
     T_ASC_PresentationContextID presId;
     T_DIMSE_C_MoveRQ    req;
@@ -1692,7 +1751,7 @@ moveSCU(T_ASC_Association *assoc, const char *fname)
 
     OFCondition cond = DIMSE_moveUser(assoc, presId, &req, dcmff.getDataset(),
         moveCallback, &callbackData, opt_blockMode, opt_dimse_timeout, net, subOpCallback,
-        NULL, &rsp, &statusDetail, &rspIds, opt_ignorePendingDatasets);
+        &secureConnection, &rsp, &statusDetail, &rspIds, opt_ignorePendingDatasets);
 
     if (cond == EC_Normal) {
 
@@ -1739,11 +1798,11 @@ moveSCU(T_ASC_Association *assoc, const char *fname)
 
 
 static OFCondition
-cmove(T_ASC_Association *assoc, const char *fname)
+cmove(T_ASC_Association *assoc, const char *fname, OFBool secureConnection)
 {
     OFCondition cond = EC_Normal;
     int n = OFstatic_cast(int, opt_repeatCount);
     while (cond.good() && n--)
-        cond = moveSCU(assoc, fname);
+        cond = moveSCU(assoc, fname, secureConnection);
     return cond;
 }
index 8969c92e3d63836d6cf69defee8167501ff92147..7a69a16144171fa551de89c758c8ed79631c3df8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* needed on Solaris for O_RDONLY */
-#endif
 
 // On Solaris with Sun Workshop 11, <signal.h> declares signal() but <csignal> does not
 #include <signal.h>
@@ -42,6 +38,7 @@ END_EXTERN_C
 #include "dcmtk/ofstd/ofstd.h"
 #include "dcmtk/ofstd/ofconapp.h"
 #include "dcmtk/ofstd/ofbmanip.h"       /* for OFBitmanipTemplate */
+#include "dcmtk/ofstd/oflist.h"
 #include "dcmtk/ofstd/ofdatime.h"
 #include "dcmtk/dcmnet/dicom.h"         /* for DICOM_APPLICATION_ACCEPTOR */
 #include "dcmtk/dcmnet/dimse.h"
@@ -114,6 +111,59 @@ enum E_SortStudyMode
     ESM_PatientName
 };
 
+#ifdef WIN32
+struct ChildProcessData
+{
+    HANDLE processHandle;
+    HANDLE waitHandle;
+    bool   done;
+};
+
+OFList< ChildProcessData * > ChildProcessList;
+HANDLE ChildProcessEvent = NULL;
+
+// This callback function will be executed by Windows in a separate thread when
+// a child process has ended, similar to the SIGCHLD callback on Posix systems
+static void CALLBACK onExitedCallback(void* context, BOOLEAN /* isTimeOut */)
+{
+    // mark the related entry for the client process that has ended as "done", i.e. ready for clean-up
+    bool *done = OFstatic_cast(bool *, context);
+    *done = true;
+
+    // if the main thread is in a blocking wait in cleanChildren() because
+    // the maximum number of child processes was running, let the main thread continue now
+    if (ChildProcessEvent) SetEvent(ChildProcessEvent);
+}
+
+// This callback function will be called in the main thread by receiveTransportConnectionTCP()
+// whenever a new child process has been create by CreateProcessA().
+// The context parameter is a pointer to the process handle, which we must store
+// and close when not needed anymore.
+static void processCreatedCallback(void *context)
+{
+    // event handler for blocking wait in cleanChildren()
+    if (ChildProcessEvent == NULL) ChildProcessEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+    // create new entry in list of child processes
+    ChildProcessData *cbd = new ChildProcessData();
+    cbd->processHandle = OFstatic_cast(HANDLE, context);
+    cbd->done = false;
+
+    // request Windows to call onExitedCallback() when the child process with the given process handle has exited
+    if (RegisterWaitForSingleObject(&cbd->waitHandle, cbd->processHandle, onExitedCallback, &cbd->done, INFINITE, WT_EXECUTEONLYONCE))
+    {
+        ChildProcessList.push_back(cbd);
+    }
+    else
+    {
+        OFLOG_WARN(storescpLogger, "RegisterWaitForSingleObject() failed, unable to track child process");
+        CloseHandle(cbd->processHandle);
+        delete cbd;
+    }
+}
+
+#endif
+
 OFBool             opt_showPresentationContexts = OFFalse;
 OFBool             opt_uniqueFilenames = OFFalse;
 OFString           opt_fileNameExtension;
@@ -172,20 +222,28 @@ OFBool             opt_forkMode = OFFalse;
 
 OFBool             opt_forkedChild = OFFalse;
 OFBool             opt_execSync = OFFalse;            // default: execute in background
-
+volatile size_t    numChildren = 0;
+OFCmdUnsignedInt   opt_maxChildren = OFstatic_cast(OFCmdUnsignedInt, -1);
 
 #ifdef HAVE_WAITPID
+
 /** signal handler for SIGCHLD signals that immediately cleans up
- *  terminated children.
+ *  terminated children and adjusts the count of child processes
  */
 extern "C" void sigChildHandler(int)
 {
-  int status = 0;
-  waitpid( -1, &status, WNOHANG );
-  signal(SIGCHLD, sigChildHandler);
+    while (waitpid( -1, NULL, WNOHANG) > 0)
+    {
+        if (numChildren > 0)
+        {
+            // In C++20, operator-- on variables with volateile qualifier is deprecated.
+            size_t n = numChildren - 1;
+            numChildren = n;
+        }
+    }
 }
-#endif
 
+#endif
 
 /* helper macro for converting stream output to a string */
 #define CONVERT_TO_STRING(output, string) \
@@ -231,9 +289,14 @@ int main(int argc, char *argv[])
 #ifdef _WIN32
     cmd.addOption("--forked-child",                        "process is forked child, internal use only", OFCommandLine::AF_Internal);
 #endif
+    cmd.addOption("--max-associations",                 1, "[m]ax: integer (default: unlimited)", "limit number of parallel associations to m");
 #endif
 
   cmd.addGroup("network options:");
+    cmd.addSubGroup("IP protocol version:");
+      cmd.addOption("--ipv4",                   "-i4",     "use IPv4 only (default)");
+      cmd.addOption("--ipv6",                   "-i6",     "use IPv6 only");
+      cmd.addOption("--ip-auto",                "-i0",     "use IPv6/IPv4 dual stack");
     cmd.addSubGroup("association negotiation profile from configuration file:");
       cmd.addOption("--config-file",            "-xf",  2, "[f]ilename, [p]rofile: string",
                                                            "use profile p from config file f");
@@ -415,6 +478,14 @@ int main(int argc, char *argv[])
     {
       opt_inetd_mode = OFTrue;
       opt_forkMode = OFFalse;
+      if (cmd.findOption("--fork"))
+      {
+        app.checkConflict("--inetd", "--fork", opt_inetd_mode);
+      }
+      if (cmd.findOption("--max-associations"))
+      {
+        app.checkDependence("--max-associations", "--fork", opt_forkMode);
+      }
 
       // duplicate stdin, which is the socket passed by inetd
       int inetd_fd = dup(0);
@@ -450,13 +521,17 @@ int main(int argc, char *argv[])
       opt_forkMode = OFFalse;
     if (cmd.findOption("--fork"))
     {
-      app.checkConflict("--inetd", "--fork", opt_inetd_mode);
       opt_forkMode = OFTrue;
     }
     cmd.endOptionBlock();
 #ifdef _WIN32
     if (cmd.findOption("--forked-child")) opt_forkedChild = OFTrue;
 #endif
+    if (cmd.findOption("--max-associations"))
+    {
+      app.checkDependence("--max-associations", "--fork", opt_forkMode);
+      app.checkValue(cmd.getValueAndCheckMin(opt_maxChildren, 1));
+    }
 #endif
 
     if (opt_inetd_mode)
@@ -549,6 +624,13 @@ int main(int argc, char *argv[])
     if (cmd.findOption("--promiscuous")) opt_promiscuous = OFTrue;
     if (cmd.findOption("--uid-padding")) opt_correctUIDPadding = OFTrue;
 
+    // set the IP protocol version
+    cmd.beginOptionBlock();
+    if (cmd.findOption("--ipv4")) dcmIncomingProtocolFamily.set(ASC_AF_INET);
+    if (cmd.findOption("--ipv6")) dcmIncomingProtocolFamily.set(ASC_AF_INET6);
+    if (cmd.findOption("--ip-auto")) dcmIncomingProtocolFamily.set(ASC_AF_UNSPEC);
+    cmd.endOptionBlock();
+
     if (cmd.findOption("--config-file"))
     {
       // check conflicts with other command line options
@@ -925,7 +1007,7 @@ int main(int argc, char *argv[])
   else
   {
     // parent process
-    if (opt_forkMode) DUL_requestForkOnTransportConnectionReceipt(argc, argv);
+    if (opt_forkMode) DUL_requestForkOnTransportConnectionReceipt(argc, argv, &processCreatedCallback);
   }
 #endif
 
@@ -953,16 +1035,35 @@ int main(int argc, char *argv[])
 
 #ifdef HAVE_WAITPID
   // register signal handler
-  signal(SIGCHLD, sigChildHandler);
+  struct sigaction sa;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+  sa.sa_handler = sigChildHandler;
+  sigaction(SIGCHLD, &sa, NULL);
 #endif
 
   while (cond.good())
   {
+#if defined(HAVE_WAITPID) || defined(WIN32)
+    /* if the maximum number of child processes is active,
+     * wait until at least one child terminates before
+     * continuing to accept incoming associations
+     */
+    if (numChildren == opt_maxChildren)
+    {
+        OFLOG_INFO(storescpLogger, "Maximum number of associations reached, waiting for child process to terminate");
+        while (numChildren == opt_maxChildren)
+        {
+            cleanChildren(-1, OFTrue);
+        }
+    }
+#endif
+
     /* receive an association and acknowledge or reject it. If the association was */
     /* acknowledged, offer corresponding services and invoke one or more if required. */
     cond = acceptAssociation(net, asccfg, tlsOptions.secureConnectionRequested());
 
-    /* remove zombie child processes */
+    /* remove zombie child processes, do not block */
     cleanChildren(-1, OFFalse);
 
     /* since storescp is usually terminated with SIGTERM or the like,
@@ -1015,7 +1116,7 @@ static OFCondition acceptAssociation(T_ASC_Network *net, DcmAssociationConfigura
   const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 10
                                      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 20
                                      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,   // 30
-                                     NULL, NULL, NULL, NULL, NULL };                               // +5
+                                     NULL, NULL, NULL, NULL, NULL, NULL };                         // +6
   int numTransferSyntaxes = 0;
 
   // try to receive an association. Here we either want to use blocking or
@@ -1027,7 +1128,11 @@ static OFCondition acceptAssociation(T_ASC_Network *net, DcmAssociationConfigura
 
   if (cond.code() == DULC_FORKEDCHILD)
   {
-    // OFLOG_DEBUG(storescpLogger, DimseCondition::dump(temp_str, cond));
+    // we are the parent process in fork mode and have successfully forked a child process
+    // that will handle the association. Just clean up the association in this process.
+    // Note: in C++20, operator++ on variables with volateile qualifier is deprecated.
+    size_t n = numChildren + 1;
+    numChildren = n;
     goto cleanup;
   }
 
@@ -1080,8 +1185,10 @@ static OFCondition acceptAssociation(T_ASC_Network *net, DcmAssociationConfigura
 
 #if defined(HAVE_FORK) || defined(_WIN32)
   if (opt_forkMode)
+  {
     OFLOG_INFO(storescpLogger, "Association Received in " << (DUL_processIsForkedChild() ? "child" : "parent")
         << " process (pid: " << OFStandard::getProcessID() << ")");
+  }
   else
 #endif
   OFLOG_INFO(storescpLogger, "Association Received");
@@ -1313,18 +1420,19 @@ static OFCondition acceptAssociation(T_ASC_Network *net, DcmAssociationConfigura
         transferSyntaxes[27] = UID_JPEGXLLosslessTransferSyntax;
         transferSyntaxes[28] = UID_JPEGXLJPEGRecompressionTransferSyntax;
         transferSyntaxes[29] = UID_JPEGXLTransferSyntax;
-        transferSyntaxes[30] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
-        transferSyntaxes[31] = UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax;
+        transferSyntaxes[30] = UID_DeflatedImageFrameCompressionTransferSyntax;
+        transferSyntaxes[31] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
+        transferSyntaxes[32] = UID_EncapsulatedUncompressedExplicitVRLittleEndianTransferSyntax;
         if (gLocalByteOrder == EBO_LittleEndian)
         {
-          transferSyntaxes[32] = UID_LittleEndianExplicitTransferSyntax;
-          transferSyntaxes[33] = UID_BigEndianExplicitTransferSyntax;
-        } else {
-          transferSyntaxes[32] = UID_BigEndianExplicitTransferSyntax;
           transferSyntaxes[33] = UID_LittleEndianExplicitTransferSyntax;
+          transferSyntaxes[34] = UID_BigEndianExplicitTransferSyntax;
+        } else {
+          transferSyntaxes[33] = UID_BigEndianExplicitTransferSyntax;
+          transferSyntaxes[34] = UID_LittleEndianExplicitTransferSyntax;
         }
-        transferSyntaxes[34] = UID_LittleEndianImplicitTransferSyntax;
-        numTransferSyntaxes = 35;
+        transferSyntaxes[35] = UID_LittleEndianImplicitTransferSyntax;
+        numTransferSyntaxes = 36;
       } else {
         /* We prefer explicit transfer syntaxes.
          * If we are running on a Little Endian machine we prefer
@@ -2457,9 +2565,12 @@ static void executeCommand( const OFString &cmd )
     OFLOG_ERROR(storescpLogger, "cannot execute command '" << cmd << "' (fork failed)");
   else if (pid > 0)
   {
-    /* we are the parent process */
-    /* remove pending zombie child processes */
-    cleanChildren(pid, opt_execSync);
+    /* we are the parent process. If we are in fork mode or
+     * in synchronous exec mode, wait for the child process to terminate
+     * and then clean up the process to avoid interference with the
+     * counter that counts the number of child process in the main process
+     */
+    cleanChildren(pid, opt_execSync || opt_forkMode);
   }
   else // in case we are the child process, execute the command etc.
   {
@@ -2501,7 +2612,7 @@ static void executeCommand( const OFString &cmd )
 #ifdef HAVE_WAITPID
 static void cleanChildren(pid_t pid, OFBool synch)
 #else
-static void cleanChildren(pid_t /* pid */, OFBool /* synch */)
+static void cleanChildren(pid_t /* pid */, OFBool synch)
 #endif
   /*
    * This function removes child processes that have terminated,
@@ -2509,23 +2620,57 @@ static void cleanChildren(pid_t /* pid */, OFBool /* synch */)
    */
 {
 #ifdef HAVE_WAITPID
-  int stat_loc;
-  int child = 1;
-  int options = synch ? 0 : WNOHANG;
-  while (child > 0)
-  {
-    child = OFstatic_cast(int, waitpid(pid, &stat_loc, options));
-    if (child < 0)
+    int stat_loc;
+    int child = 1;
+    int options = synch ? 0 : WNOHANG;
+    while (child > 0)
     {
-      if (errno != ECHILD)
+      child = OFstatic_cast(int, waitpid(pid, &stat_loc, options));
+      if (child > 0)
       {
-        char buf[256];
-        OFLOG_WARN(storescpLogger, "wait for child failed: " << OFStandard::strerror(errno, buf, sizeof(buf)));
+        if (numChildren > 0)
+        {
+          // In C++20, operator-- on variables with volateile qualifier is deprecated.
+          size_t n = numChildren - 1;
+          numChildren = n;
+        }
+      }
+      else if (child < 0)
+      {
+        if (errno != ECHILD)
+        {
+          char buf[256];
+          OFLOG_WARN(storescpLogger, "wait for child failed: " << OFStandard::strerror(errno, buf, sizeof(buf)));
+        }
       }
+      if (synch) options = 0; // break out of loop
+    }
+#elif defined(WIN32)
+    if (synch && ChildProcessEvent)
+    {
+        // block until a child process has ended
+        WaitForSingleObject(ChildProcessEvent, INFINITE);
+    }
+    OFListIterator(ChildProcessData *) first = ChildProcessList.begin();
+    OFListIterator(ChildProcessData *) last = ChildProcessList.end();
+    while (first != last)
+    {
+        if ((*first)->done)
+        {
+            // clean up wait handle
+            UnregisterWaitEx((*first)->waitHandle, INVALID_HANDLE_VALUE);
+            // close process handle
+            CloseHandle((*first)->processHandle);
+            // delete list entry
+            delete *first;
+            first = ChildProcessList.erase(first);
+            // decrease counter for child processes
+            // Note: in C++20, operator-- on variables with volateile qualifier is deprecated.
+            size_t n = numChildren - 1;
+            numChildren = n;
+        }
+        else ++first;
     }
-
-    if (synch) child = -1; // break out of loop
-  }
 #endif
 }
 
index 037553b47bfe32d0fd570930d2ea1ca331e133d0..9be99c864fea63826e50b86bb4eabc5d49b531b9 100644 (file)
@@ -63,6 +63,17 @@ port  tcp/ip port number to listen on
 
 \subsection dcmrecv_network_options network options
 \verbatim
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profile from configuration file:
 
   -xf   --config-file  [f]ilename, [p]rofile: string
@@ -480,6 +491,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmrecv_copyright COPYRIGHT
 
-Copyright (C) 2013-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2013-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index b98db6ef72d216b7fe7f1666f8d9fc2599486471..72a599ac1814ce448f85b062a6aee5b7f13283ff 100644 (file)
@@ -420,6 +420,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmsend_copyright COPYRIGHT
 
-Copyright (C) 2011-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2011-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 0886cd1bd3905bd07518130c832c3f4df1bbd2b3..9a12a9dea3aca378164d45c4d2d13dfd3e4c6e44 100644 (file)
@@ -80,7 +80,7 @@ application entity titles:
 
 association negotiation debugging:
 
-  -pts  --propose-ts  [n]umber: integer (1..52)
+  -pts  --propose-ts  [n]umber: integer (1..53)
           propose n transfer syntaxes
 
   -ppc  --propose-pc  [n]umber: integer (1..128)
@@ -405,6 +405,6 @@ It is an error if no data dictionary can be loaded.
 
 \section echoscu_copyright COPYRIGHT
 
-Copyright (C) 1994-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1994-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 321df261951811330a132cb78671396ad57ad569..4c921cd43f5d9d493a1d19cbb06989b966a03df9 100644 (file)
@@ -508,6 +508,6 @@ replace any built-in tables.
 
 \section findscu_copyright COPYRIGHT
 
-Copyright (C) 1994-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1994-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index c7ef7ae51512b81033d819eb85c4a8181df0b4a3..f5d178c15b02199663f308ebc6e05432ba0df1be 100644 (file)
@@ -476,6 +476,8 @@ BasicVoiceAudioWaveformStorage                       1.2.840.10008.5.1.4.1.1.9.4
 GeneralAudioWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.4.2
 ArterialPulseWaveformStorage                         1.2.840.10008.5.1.4.1.1.9.5.1
 RespiratoryWaveformStorage                           1.2.840.10008.5.1.4.1.1.9.6.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -683,6 +685,6 @@ It is an error if no data dictionary can be loaded.
 
 \section getscu_copyright COPYRIGHT
 
-Copyright (C) 2011-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2011-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7ff1be4df7be8a51ecc11ac32ecae525a9a7f331..643b20874e6f69c50a4aff174f1049a9dd9904b7 100644 (file)
@@ -67,6 +67,17 @@ dcmfile-in  DICOM query file(s)
 
 \subsection movescu_network_options network options
 \verbatim
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 override matching keys:
 
   -k    --key  [k]ey: gggg,eeee="str" or dictionary name="str"
@@ -241,6 +252,130 @@ other network options:
           silently correct space-padded UIDs
 \endverbatim
 
+\subsection movescu_tls_options transport layer security (TLS) options
+\verbatim
+transport protocol stack:
+
+  -tls  --disable-tls
+          use normal TCP/IP connection (default)
+
+  +tls  --enable-tls  [p]rivate key file, [c]ertificate file: string
+          use authenticated secure TLS connection
+
+private key password (only with --enable-tls):
+
+  +ps   --std-passwd
+          prompt user to type password on stdin (default)
+
+  +pw   --use-passwd  [p]assword: string
+          use specified password
+
+  -pw   --null-passwd
+          use empty string as password
+
+key and certificate file format:
+
+  -pem  --pem-keys
+          read keys and certificates as PEM file (default)
+
+  -der  --der-keys
+          read keys and certificates as DER file
+
+certification authority:
+
+  +cf   --add-cert-file  [f]ilename: string
+          add certificate file to list of certificates
+
+  +cd   --add-cert-dir  [d]irectory: string
+          add certificates in d to list of certificates
+
+  +crl  --add-crl-file  [f]ilename: string
+          add certificate revocation list file
+          (implies --enable-crl-vfy)
+
+  +crv  --enable-crl-vfy
+          enable leaf CRL verification
+
+  +cra  --enable-crl-all
+          enable full chain CRL verification
+
+security profile:
+
+  +ph   --list-profiles
+          list supported TLS profiles and exit
+
+  +pg   --profile-8996
+          BCP 195 RFC 8996 TLS Profile (default)
+
+  +pm   --profile-8996-mod
+          Modified BCP 195 RFC 8996 TLS Profile
+
+          # only available if underlying TLS library supports
+          # all TLS features required for this profile
+
+  +py   --profile-bcp195-nd
+          Non-downgrading BCP 195 TLS Profile (retired)
+
+  +px   --profile-bcp195
+          BCP 195 TLS Profile (retired)
+
+  +pz   --profile-bcp195-ex
+          Extended BCP 195 TLS Profile (retired)
+
+  +pb   --profile-basic
+          Basic TLS Secure Transport Connection Profile (retired)
+
+          # only available if underlying TLS library supports 3DES
+
+  +pa   --profile-aes
+          AES TLS Secure Transport Connection Profile (retired)
+
+  +pn   --profile-null
+          Authenticated unencrypted communication
+          (retired, was used in IHE ATNA)
+
+ciphersuite:
+
+  +cc   --list-ciphers
+          list supported TLS ciphersuites and exit
+
+  +cs   --cipher  [c]iphersuite name: string
+          add ciphersuite to list of negotiated suites
+
+  +dp   --dhparam  [f]ilename: string
+          read DH parameters for DH/DSS ciphersuites
+
+server name indication:
+
+        --no-sni
+          do not use SNI (default)
+
+        --expect-sni  [s]erver name: string
+          expect requests for server name s
+
+pseudo random generator:
+
+  +rs   --seed  [f]ilename: string
+          seed random generator with contents of f
+
+  +ws   --write-seed
+          write back modified seed (only with --seed)
+
+  +wf   --write-seed-file  [f]ilename: string (only with --seed)
+          write modified seed to file f
+
+peer authentication:
+
+  -rc   --require-peer-cert
+          verify peer certificate, fail if absent (default)
+
+  -vc   --verify-peer-cert
+          verify peer certificate if present
+
+  -ic   --ignore-peer-cert
+          don't verify peer certificate
+\endverbatim
+
 \subsection movescu_output_options output options
 \verbatim
 general:
@@ -480,6 +615,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -627,6 +764,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -685,6 +823,7 @@ HighThroughputJPEG2000ImageCompressionLossless.Tr.S. 1.2.840.10008.1.2.4.201
 HighThroughputJPEG2000RPCLImageCompressionLoss.Tr.S. 1.2.840.10008.1.2.4.202
 HighThroughputJPEG2000ImageCompressionTransferSynta. 1.2.840.10008.1.2.4.203
 RLELosslessTransferSyntax                            1.2.840.10008.1.2.5
+DeflatedImageFrameCompressionTransferSyntax          1.2.840.10008.1.2.8.1
 \endverbatim
 
 (*) if compiled with zlib support enabled (see \e --version output)
@@ -789,6 +928,7 @@ EXITCODE_NO_PRESENTATION_CONTEXT         66
 EXITCODE_CANNOT_CLOSE_ASSOCIATION        67
 EXITCODE_CMOVE_WARNING                   68
 EXITCODE_CMOVE_ERROR                     69
+EXITCODE_CANNOT_CREATE_TLS_LAYER         70
 \endverbatim
 
 \section movescu_environment ENVIRONMENT
@@ -813,6 +953,6 @@ It is an error if no data dictionary can be loaded.
 
 \section movescu_copyright COPYRIGHT
 
-Copyright (C) 1994-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1994-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index fb09d07d44689e114698336d0c2e3d1b26e4a7be..ecd4113b8f167c1213aa32b8cc81f498de249d41 100644 (file)
@@ -67,10 +67,24 @@ port  tcp/ip port number to listen on
 
         --fork
           fork child process for each association
+
+        --max-associations  [m]ax: integer (default: unlimited)
+          limit number of parallel associations to m
 \endverbatim
 
 \subsection storescp_network_options network options
 \verbatim
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profile from configuration file:
 
   -xf   --config-file  [f]ilename [p]rofile: string
@@ -685,6 +699,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -832,6 +848,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -890,6 +907,7 @@ HighThroughputJPEG2000ImageCompressionLossless.Tr.S. 1.2.840.10008.1.2.4.201
 HighThroughputJPEG2000RPCLImageCompressionLoss.Tr.S. 1.2.840.10008.1.2.4.202
 HighThroughputJPEG2000ImageCompressionTransferSynta. 1.2.840.10008.1.2.4.203
 RLELosslessTransferSyntax                            1.2.840.10008.1.2.5
+DeflatedImageFrameCompressionTransferSyntax          1.2.840.10008.1.2.8.1
 \endverbatim
 
 (*) if compiled with zlib support enabled (see \e --version output)
@@ -1013,6 +1031,6 @@ It is an error if no data dictionary can be loaded.
 
 \section storescp_copyright COPYRIGHT
 
-Copyright (C) 1996-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1996-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7f0fbefe5f9667646b2ca79d8341cf3b7be48fa7..f12a47f24b09388490963c33e0c4d3a2711c6df5 100644 (file)
@@ -638,6 +638,6 @@ It is an error if no data dictionary can be loaded.
 
 \section storescu_copyright COPYRIGHT
 
-Copyright (C) 1996-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1996-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 09a16a6da3201d45e9b4deb576055b6bf1c1e2c4..a7f76f832dd51fbbd2924850166ef4d0be59d6a4 100644 (file)
@@ -154,6 +154,6 @@ It is an error if no data dictionary can be loaded.
 
 \section termscu_copyright COPYRIGHT
 
-Copyright (C) 2005-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2005-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7265661fccd7e0f2a10dc1fb530b1872e78a73b7..c2584b49282eefa0a3cf454868365719cfdbfd93 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2003-2024, OFFIS e.V.
+#  Copyright (C) 2003-2025, OFFIS e.V.
 #  All rights reserved.  See COPYRIGHT file for details.
 #
 #  This software and supporting documentation were developed by
@@ -44,6 +44,9 @@ TransferSyntax1  = DeflatedLittleEndianExplicit
 TransferSyntax2  = LocalEndianExplicit
 TransferSyntax3  = OppositeEndianExplicit
 TransferSyntax4  = LittleEndianImplicit
+#
+# The "Deflated Image Frame Compression" transfer syntax is for images.
+#
 
 [UncompressedEncapsulatedOrZlib]
 TransferSyntax1  = DeflatedLittleEndianExplicit
@@ -53,6 +56,8 @@ TransferSyntax4  = LittleEndianImplicit
 #
 # The retired "Big Endian Explicit" transfer syntax is not accepted.
 #
+# The "Deflated Image Frame Compression" transfer syntax is for images.
+#
 
 [AnyTransferSyntax]
 TransferSyntax1  = JPEGBaseline
@@ -102,11 +107,12 @@ TransferSyntax44 = HighThroughputJPEG2000ImageCompression
 TransferSyntax45 = JPEGXLLossless
 TransferSyntax46 = JPEGXLJPEGRecompression
 TransferSyntax47 = JPEGXL
-TransferSyntax48 = DeflatedLittleEndianExplicit
-TransferSyntax49 = EncapsulatedUncompressedLittleEndianExplicit
-TransferSyntax50 = LocalEndianExplicit
-TransferSyntax51 = OppositeEndianExplicit
-TransferSyntax52 = LittleEndianImplicit
+TransferSyntax48 = DeflatedImageFrameCompression
+TransferSyntax49 = DeflatedLittleEndianExplicit
+TransferSyntax50 = EncapsulatedUncompressedLittleEndianExplicit
+TransferSyntax51 = LocalEndianExplicit
+TransferSyntax52 = OppositeEndianExplicit
+TransferSyntax53 = LittleEndianImplicit
 
 # ============================================================================
 [[PresentationContexts]]
@@ -309,46 +315,49 @@ PresentationContext178 = TwelveLeadECGWaveformStorage\UncompressedOrZlib
 PresentationContext179 = VariableModalityLUTSoftcopyPresentationStateStorage\UncompressedOrZlib
 PresentationContext180 = VisualAcuityMeasurementsStorage\UncompressedOrZlib
 PresentationContext181 = VolumeRenderingVolumetricPresentationStateStorage\UncompressedOrZlib
-PresentationContext182 = WaveformAnnotationSRStorage\UncompressedOrZlib
-PresentationContext183 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext184 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext185 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
-PresentationContext186 = XRayRadiationDoseSRStorage\UncompressedOrZlib
+PresentationContext182 = WaveformAcquisitionPresentationStateStorage\UncompressedOrZlib
+PresentationContext183 = WaveformAnnotationSRStorage\UncompressedOrZlib
+PresentationContext184 = WaveformPresentationStateStorage\UncompressedOrZlib
+PresentationContext185 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext186 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext187 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
+PresentationContext188 = XRayRadiationDoseSRStorage\UncompressedOrZlib
 #
 # retired non-image SOP classes
 #
-PresentationContext187 = RETIRED_StandaloneCurveStorage\UncompressedOrZlib
-PresentationContext188 = RETIRED_StandaloneModalityLUTStorage\UncompressedOrZlib
-PresentationContext189 = RETIRED_StandaloneOverlayStorage\UncompressedOrZlib
-PresentationContext190 = RETIRED_StandalonePETCurveStorage\UncompressedOrZlib
-PresentationContext191 = RETIRED_StandaloneVOILUTStorage\UncompressedOrZlib
-PresentationContext192 = RETIRED_StoredPrintStorage\UncompressedOrZlib
+PresentationContext189 = RETIRED_StandaloneCurveStorage\UncompressedOrZlib
+PresentationContext190 = RETIRED_StandaloneModalityLUTStorage\UncompressedOrZlib
+PresentationContext191 = RETIRED_StandaloneOverlayStorage\UncompressedOrZlib
+PresentationContext192 = RETIRED_StandalonePETCurveStorage\UncompressedOrZlib
+PresentationContext193 = RETIRED_StandaloneVOILUTStorage\UncompressedOrZlib
+PresentationContext194 = RETIRED_StoredPrintStorage\UncompressedOrZlib
 #
 # draft non-image SOP classes
 #
-PresentationContext193 = DRAFT_RTBeamsDeliveryInstructionStorage\UncompressedOrZlib
-PresentationContext194 = DRAFT_SRAudioStorage\UncompressedOrZlib
-PresentationContext195 = DRAFT_SRComprehensiveStorage\UncompressedOrZlib
-PresentationContext196 = DRAFT_SRDetailStorage\UncompressedOrZlib
-PresentationContext197 = DRAFT_SRTextStorage\UncompressedOrZlib
-PresentationContext198 = DRAFT_WaveformStorage\UncompressedOrZlib
+PresentationContext195 = DRAFT_RTBeamsDeliveryInstructionStorage\UncompressedOrZlib
+PresentationContext196 = DRAFT_SRAudioStorage\UncompressedOrZlib
+PresentationContext197 = DRAFT_SRComprehensiveStorage\UncompressedOrZlib
+PresentationContext198 = DRAFT_SRDetailStorage\UncompressedOrZlib
+PresentationContext199 = DRAFT_SRTextStorage\UncompressedOrZlib
+PresentationContext200 = DRAFT_WaveformStorage\UncompressedOrZlib
 #
 # DICOS Storage
 #
-PresentationContext199 = DICOS_CTImageStorage\AnyTransferSyntax
-PresentationContext200 = DICOS_DigitalXRayImageStorageForPresentation\AnyTransferSyntax
-PresentationContext201 = DICOS_DigitalXRayImageStorageForProcessing\AnyTransferSyntax
-PresentationContext202 = DICOS_2DAITStorage\AnyTransferSyntax
-PresentationContext203 = DICOS_3DAITStorage\AnyTransferSyntax
-PresentationContext204 = DICOS_QuadrupoleResonanceStorage\UncompressedOrZlib
-PresentationContext205 = DICOS_ThreatDetectionReportStorage\UncompressedOrZlib
+PresentationContext201 = DICOS_CTImageStorage\AnyTransferSyntax
+PresentationContext202 = DICOS_DigitalXRayImageStorageForPresentation\AnyTransferSyntax
+PresentationContext203 = DICOS_DigitalXRayImageStorageForProcessing\AnyTransferSyntax
+PresentationContext204 = DICOS_2DAITStorage\AnyTransferSyntax
+PresentationContext205 = DICOS_3DAITStorage\AnyTransferSyntax
+PresentationContext206 = DICOS_QuadrupoleResonanceStorage\UncompressedOrZlib
+PresentationContext207 = DICOS_ThreatDetectionReportStorage\UncompressedOrZlib
 #
 # DICONDE Storage
 #
-PresentationContext206 = DICONDE_EddyCurrentImageStorage\AnyTransferSyntax
-PresentationContext207 = DICONDE_EddyCurrentMultiframeImageStorage\AnyTransferSyntax
-PresentationContext208 = DICONDE_ThermographyImageStorage\AnyTransferSyntax
-PresentationContext209 = DICONDE_ThermographyMultiFrameImageStorage\AnyTransferSyntax
+PresentationContext208 = DICONDE_EddyCurrentImageStorage\AnyTransferSyntax
+PresentationContext209 = DICONDE_EddyCurrentMultiframeImageStorage\AnyTransferSyntax
+PresentationContext210 = DICONDE_ThermographyImageStorage\AnyTransferSyntax
+PresentationContext211 = DICONDE_ThermographyMultiFrameImageStorage\AnyTransferSyntax
+PresentationContext212 = DICONDE_UltrasoundWaveformStorage\UncompressedOrZlib
 
 # ----------------------------------------------------------------------------
 
@@ -542,11 +551,13 @@ PresentationContext170 = TwelveLeadECGWaveformStorage\UncompressedOrZlib
 PresentationContext171 = VariableModalityLUTSoftcopyPresentationStateStorage\UncompressedOrZlib
 PresentationContext172 = VisualAcuityMeasurementsStorage\UncompressedOrZlib
 PresentationContext173 = VolumeRenderingVolumetricPresentationStateStorage\UncompressedOrZlib
-PresentationContext174 = WaveformAnnotationSRStorage\UncompressedOrZlib
-PresentationContext175 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext176 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext177 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
-PresentationContext178 = XRayRadiationDoseSRStorage\UncompressedOrZlib
+PresentationContext174 = WaveformAcquisitionPresentationStateStorage\UncompressedOrZlib
+PresentationContext175 = WaveformAnnotationSRStorage\UncompressedOrZlib
+PresentationContext176 = WaveformPresentationStateStorage\UncompressedOrZlib
+PresentationContext177 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext178 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext179 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
+PresentationContext180 = XRayRadiationDoseSRStorage\UncompressedOrZlib
 
 # ============================================================================
 [[Profiles]]
index 412ec319f7b10cd21c9240e73d98ad7f9c7c8c69..a912e2de5c1f72c18029d9d34e4f630b8d4f9067 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2003-2024, OFFIS e.V.
+#  Copyright (C) 2003-2025, OFFIS e.V.
 #  All rights reserved.  See COPYRIGHT file for details.
 #
 #  This software and supporting documentation were developed by
@@ -81,6 +81,7 @@ TransferSyntax1 = MPEG4HighProfile/Level4.1
 # - EncapsulatedUncompressedLittleEndianExplicit
 #
 # - DeflatedLittleEndianExplicit
+# - DeflatedImageFrameCompression
 #
 # - JPEGBaseline
 # - JPEGExtended:Process2+4
@@ -384,7 +385,9 @@ PresentationContext128 = VideoPhotographicImageStorage\MPEG2
 # - VisualAcuityMeasurementsStorage
 # - VLWholeSlideMicroscopyImageStorage
 # - VolumeRenderingVolumetricPresentationStateStorage
+# - WaveformAcquisitionPresentationStateStorage
 # - WaveformAnnotationSRStorage
+# - WaveformPresentationStateStorage
 # - WideFieldOphthalmicPhotographyStereographicProjectionImageStorage
 # - WideFieldOphthalmicPhotography3DCoordinatesImageStorage
 # - XADefinedProcedureProtocolStorage
@@ -419,6 +422,7 @@ PresentationContext128 = VideoPhotographicImageStorage\MPEG2
 # - DICONDE_EddyCurrentMultiframeImageStorage
 # - DICONDE_ThermographyImageStorage
 # - DICONDE_ThermographyMultiFrameImageStorage
+# - DICONDE_UltrasoundWaveformStorage
 
 # ============================================================================
 [[Profiles]]
index b77d674144e6dceab1f08d13bce8c05c602113f5..9483b008a64cd35d5810771092ab099e807bb4f7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
@@ -218,6 +218,13 @@ struct DCMTK_DCMNET_EXPORT T_ASC_RejectParameters
     T_ASC_RejectParametersReason reason;
 };
 
+struct DCMTK_DCMNET_EXPORT T_ASC_ImplementationIdentification
+{
+    T_ASC_ImplementationIdentification();
+
+    DIC_UI ourImplementationClassUID;
+    DIC_SH ourImplementationVersionName;
+};
 
 struct DCMTK_DCMNET_EXPORT T_ASC_Parameters
 {
@@ -295,7 +302,8 @@ DCMTK_DCMNET_EXPORT OFCondition
 ASC_createAssociationParameters(
     T_ASC_Parameters ** params,
     long maxReceivePDUSize,
-    Sint32 tcpConnectTimeout);
+    Sint32 tcpConnectTimeout,
+    const T_ASC_ImplementationIdentification& implIdentification = T_ASC_ImplementationIdentification());
 
 /*
  * same as before, but uses value of the global dcmConnectionTimeout variable.
@@ -697,7 +705,8 @@ ASC_receiveAssociation(
     unsigned long *associatePDUlength=NULL,
     OFBool useSecureLayer=OFFalse,
     DUL_BLOCKOPTIONS block=DUL_BLOCK,
-    int timeout=0);
+    int timeout=0,
+    const T_ASC_ImplementationIdentification& implIdentification = T_ASC_ImplementationIdentification());
 
 DCMTK_DCMNET_EXPORT OFCondition
 ASC_acknowledgeAssociation(
index c083c16afebfe1658ed78b3065f54e4954f7cdf2..bb62499b3657024c1e2d73d588d3cc452f3c2946 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
@@ -96,9 +96,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SOCKET_H
 #ifndef DCOMPAT_SYS_SOCKET_H_
 #define DCOMPAT_SYS_SOCKET_H_
@@ -184,18 +182,6 @@ END_EXTERN_C
 #endif
 #endif
 
-#ifndef HAVE_ACCESS
-
-#ifndef R_OK
-#define R_OK 0x01
-#define W_OK 0x02
-#define X_OK 0x04
-#define F_OK 0x08
-#endif
-
-DCMTK_DCMNET_EXPORT int access(const char* path, int amode);
-#else /* HAVE_ACCESS */
-
 #ifdef _WIN32
 /* windows defines access but not the constants */
 #ifndef R_OK
@@ -206,8 +192,6 @@ DCMTK_DCMNET_EXPORT int access(const char* path, int amode);
 #endif /* R_OK */
 #endif /* _WIN32 */
 
-#endif /* HAVE_ACCESS */
-
 #ifdef _WIN32
 #define NULL_DEVICE_NAME "nul"
 #else
index 745c4998c11b565417a6695a8e088aaf4e617ffd..5c16673b44612ce3037a6a1d7dfcc81bf5423480 100644 (file)
@@ -130,9 +130,29 @@ extern DCMTK_DCMNET_EXPORT OFGlobal<unsigned long> dcmEnableBackwardCompatibilit
  */
 extern DCMTK_DCMNET_EXPORT OFGlobal<size_t> dcmAssociatePDUSizeLimit;   /* default: 1 MB */
 
+/** TCP/IP protocol family to be used for network connections
+ */
+enum T_ASC_ProtocolFamily
+{
+  /// default behaviour. Currently identical to ASC_AF_INET
+  ASC_AF_Default,
+  /// only use IPv4
+  ASC_AF_INET,
+  /// only use IPv6
+  ASC_AF_INET6,
+  /// dual-stack operation, automatically select IPv4 or IPv6
+  ASC_AF_UNSPEC
+};
+
+/** TCP/IP protocol family to be supported for incoming network
+ *  connections in association acceptors.
+ */
+extern DCMTK_DCMNET_EXPORT OFGlobal<T_ASC_ProtocolFamily> dcmIncomingProtocolFamily;
+
 typedef void DUL_NETWORKKEY;
 typedef void DUL_ASSOCIATIONKEY;
 typedef unsigned char DUL_PRESENTATIONCONTEXTID;
+typedef void (*DUL_CREATEPROCESS_CALLBACK)(void *);
 
 /** pure virtual base class for DUL mode callbacks
  */
@@ -176,15 +196,6 @@ public:
   virtual void callback(unsigned long mode) = 0;
 };
 
-enum T_ASC_ProtocolFamily
-{
-  ASC_AF_Default,
-  ASC_AF_INET,
-  ASC_AF_INET6,
-  ASC_AF_UNSPEC
-};
-
-
 typedef struct {
     char applicationContextName[DUL_LEN_NAME + 1];
     char callingAPTitle[DUL_LEN_TITLE + 1];
@@ -573,8 +584,10 @@ DCMTK_DCMNET_EXPORT OFCondition DUL_readSocketHandleAsForkedChild();
  *     The content of this parameter is ignored on Posix platforms but required
  *     on Win32, where the child process is created with CreateProcess and the
  *     command line parameters have to be passed from parent to child.
+ *  @param pointer to a callback function that will be called on Windows
+ *     when a child process has been created using CreateProcessA().
  */
-DCMTK_DCMNET_EXPORT void DUL_requestForkOnTransportConnectionReceipt(int argc, char *argv[]);
+DCMTK_DCMNET_EXPORT void DUL_requestForkOnTransportConnectionReceipt(int argc, char *argv[], DUL_CREATEPROCESS_CALLBACK cb = NULL);
 
 /** this function sets a flag in the association that the current process
  *  is the parent process after a fork() operation and that the association
index 527ce1117ce6afde4265d92875dc97fb589e9f85..316ec7b12eb22903972989ac60797edc18a55580 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2009-2023, OFFIS e.V.
+ *  Copyright (C) 2009-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -322,7 +322,7 @@ public:
     void setACSETimeout(const Uint32 acseTimeout);
 
     /** Set the timeout that should be waited for connection requests.
-     *  Only relevant in non-blocking mode (default).
+     *  Only relevant in non-blocking mode (which is not the default).
      *  @param timeout [in] TCP/IP connection timeout in seconds.
      */
     void setConnectionTimeout(const Uint32 timeout);
index fdbda46637fab5c7c5d94ad891d3cee461761a93..a43172a29717ec3a0830ca3d7e9ecaefb766d7a9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2022, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -140,6 +140,16 @@ public:
   OFCondition checkAssociationProfile(const OFString &profileName,
                                       OFString& mangledName) const;
 
+  /** Set association implementation identification parameters
+   *  @param implIdentification [in] Implementation Class UID and Implementation Version Name
+   */
+  void setImplementationIdentification(const T_ASC_ImplementationIdentification& implIdentification);
+
+  /** Returns association implementation identification parameters
+   *  @return Implementation Class UID and Implementation Version Name
+   */
+  const T_ASC_ImplementationIdentification& getImplementationIdentification() const;
+
   /** Force every association request to be refused by SCP, no matter what the SCU is
    *  offering
    *  @param doRefuse [in] If OFTrue, every association is being refused. DcmSCP's default
@@ -187,7 +197,7 @@ public:
   void setACSETimeout(const Uint32 acseTimeout);
 
   /** Set the timeout that should be waited for connection requests.
-   *  Only relevant in non-blocking mode (default).
+   *  Only relevant in non-blocking mode (which is not the default).
    *  @param timeout [in] TCP/IP connection timeout in seconds.
    */
   void setConnectionTimeout(const Uint32 timeout);
@@ -360,6 +370,9 @@ protected:
   /// called "DEFAULT" is used.
   OFString m_assocCfgProfileName;
 
+  /// Implementation Class UID and Implementation Version Name
+  T_ASC_ImplementationIdentification m_implIdentification;
+
   /// Port on which the SCP is listening for association requests. The default port is 104.
   Uint16 m_port;
 
index f6613f941068e941fab69ce690c8effbbded4aee..fe126766d57b93f09ce47fc29191e9d16d0eec11 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2018, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -83,6 +83,9 @@ public:
        */
       virtual void exit();
 
+      /** Restart the worker thread */
+      virtual void rerun();
+
     protected:
 
       /** Protected constructor which is called within the friend class
@@ -210,7 +213,7 @@ protected:
    *                exit.
    *  @param result The final result of the thread.
    */
-  void notifyThreadExit(DcmBaseSCPWorker* thread,
+  void notifyWorkerDone(DcmBaseSCPWorker* thread,
                         OFCondition result);
 
   /** Initialize network, i.e. create an instance of T_ASC_Network and set
@@ -218,7 +221,7 @@ protected:
    *  @param network The T_ASC_Network pointer to create the instance
    *  @return EC_Normal if there were no errors during initialization.
    */
-  virtual OFCondition initializeNework(T_ASC_Network** network);
+  virtual OFCondition initializeNetwork(T_ASC_Network** network);
 
 private:
 
@@ -257,7 +260,10 @@ private:
   // OFList<T_ASC_Association*> m_waiting;
 
   /// Current run mode of pool
-  runmode m_runMode;
+  volatile runmode m_runMode;
+
+  /// Set m_runMode to SHUTDOWN on return from listen function
+  void finishListening();
 };
 
 /** Implementation of DICOM SCP server pool. The pool waits for incoming
@@ -324,6 +330,8 @@ private:
         }
 
         /** Perform SCP's duties on an already accepted (TCP/IP) connection.
+         *  Once done, destroy the association so the worker does not appear blocked
+         *  for the next request in case of reuse.
          *  @param assoc The association to be run
          *  @return Returns EC_Normal if negotiation could take place and no
          *          serious network error has occurred or the given association
@@ -331,7 +339,9 @@ private:
          */
         virtual OFCondition workerListen(T_ASC_Association* const assoc)
         {
-            return SCP::run(assoc);
+            OFCondition result = SCP::run(assoc);
+            SCP::dropAndDestroyAssociation();
+            return result;
         }
     };
 
index 13b0ed518345a5f61abf6e145e987f9cfc784578..9aa9c1ae1f671e9c38959899451a658edee04ced 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2013, OFFIS e.V.
+ *  Copyright (C) 2013-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -70,6 +70,15 @@ public:
    */
   virtual OFCondition setSharedConfig(const DcmSharedSCPConfig& config);
 
+protected:
+
+  /** Drops association and clears internal structures to free memory,
+   *  resets internal m_assoc pointer to NULL so that isConnected()
+   *  will return false after this call. Exposed from DcmSCP in order
+   *  to enforce proper cleanup from derived classes.
+   */
+  virtual void dropAndDestroyAssociation();
+
 private:
 
   /** Private undefined copy constructor. Shall never be called.
index 73c48dcf81c46def156c6549797b970ee63c48b3..5a83c25a8163fc85bbae7f70c88b6ced042dea35 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2008-2024, OFFIS e.V.
+ *  Copyright (C) 2008-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -701,6 +701,11 @@ public:
      */
     void setAssocConfigFileAndProfile(const OFString& filename, const OFString& profile);
 
+    /** Set association implementation identification parameters
+     *  @param implIdentification [in] Implementation Class UID and Implementation Version Name
+     */
+    void setImplementationIdentification(const T_ASC_ImplementationIdentification& implIdentification);
+
     /** Set the directory that should be used by the standard C-GET handler to store objects
      *  that come in with the corresponding C-STORE requests
      *  @param storeDir [in] The directory to store to. It is checked in handleSTORERequest()
@@ -1076,6 +1081,9 @@ private:
     /// Configuration file containing association parameters
     OFString m_assocConfigFile;
 
+    /// Implementation Class UID and Implementation Version Name
+    T_ASC_ImplementationIdentification m_implIdentification;
+
     /// The last DIMSE successfully sent, unresponded DIMSE request
     T_DIMSE_Message* m_openDIMSERequest;
 
index e86b42a6677cf221c822ab5334c3637625568151..5497c0ad08e5e23ce4585897bc0e4caef5e4c166 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -209,6 +207,22 @@ typedef struct {
 } T_ASC_ExtendedNegotiationItem;
 
 
+T_ASC_ImplementationIdentification::T_ASC_ImplementationIdentification()
+{
+    OFStandard::strlcpy(ourImplementationClassUID,
+        OFFIS_IMPLEMENTATION_CLASS_UID,
+        sizeof(ourImplementationClassUID));
+    OFStandard::strlcpy(ourImplementationVersionName,
+        OFFIS_DTK_IMPLEMENTATION_VERSION_NAME,
+        sizeof(ourImplementationVersionName));
+
+    if (strlen(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME) > 16)
+    {
+        DCMNET_WARN("DICOM implementation version name too long: " << OFFIS_DTK_IMPLEMENTATION_VERSION_NAME);
+    }
+}
+
+
 /*
 ** Function Bodies
 */
@@ -274,25 +288,20 @@ ASC_dropNetwork(T_ASC_Network ** network)
 OFCondition
 ASC_createAssociationParameters(T_ASC_Parameters ** params,
                                 long maxReceivePDUSize,
-                                Sint32 tcpConnectTimeout)
+                                Sint32 tcpConnectTimeout,
+                                const T_ASC_ImplementationIdentification& implIdentification)
 {
-
     *params = (T_ASC_Parameters *) malloc(sizeof(**params));
     if (*params == NULL) return EC_MemoryExhausted;
     memset((char*)*params, 0, sizeof(**params));
 
     OFStandard::strlcpy((*params)->ourImplementationClassUID,
-            OFFIS_IMPLEMENTATION_CLASS_UID,
+            implIdentification.ourImplementationClassUID,
             sizeof((*params)->ourImplementationClassUID));
     OFStandard::strlcpy((*params)->ourImplementationVersionName,
-            OFFIS_DTK_IMPLEMENTATION_VERSION_NAME,
+            implIdentification.ourImplementationVersionName,
             sizeof((*params)->ourImplementationVersionName));
 
-    if (strlen(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME) > 16)
-    {
-      DCMNET_WARN("DICOM implementation version name too long: " << OFFIS_DTK_IMPLEMENTATION_VERSION_NAME);
-    }
-
     OFStandard::strlcpy((*params)->DULparams.callingImplementationClassUID,
         (*params)->ourImplementationClassUID, DICOM_UI_LENGTH + 1);
     OFStandard::strlcpy((*params)->DULparams.callingImplementationVersionName,
@@ -1753,7 +1762,8 @@ ASC_receiveAssociation(T_ASC_Network * network,
                        unsigned long *associatePDUlength,
                        OFBool useSecureLayer,
                        DUL_BLOCKOPTIONS block,
-                       int timeout)
+                       int timeout,
+                       const T_ASC_ImplementationIdentification& implIdentification)
 {
     T_ASC_Parameters *params;
     DUL_ASSOCIATIONKEY *DULassociation;
@@ -1763,7 +1773,7 @@ ASC_receiveAssociation(T_ASC_Network * network,
     int retrieveRawPDU = 0;
     if (associatePDU && associatePDUlength) retrieveRawPDU = 1;
 
-    OFCondition cond = ASC_createAssociationParameters(&params, maxReceivePDUSize, dcmConnectionTimeout.get());
+    OFCondition cond = ASC_createAssociationParameters(&params, maxReceivePDUSize, dcmConnectionTimeout.get(), implIdentification);
     if (cond.bad()) return cond;
 
     cond = ASC_setTransportLayerType(params, useSecureLayer);
index 15e3ed99657cc460c19c24e8f947462bcbfe7cd0..9212bfb53b4180063b73b402a9e222b4d3388e06 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -38,9 +38,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -147,38 +145,28 @@ DcmTransportConnection::~DcmTransportConnection()
 
 OFBool DcmTransportConnection::safeSelectReadableAssociation(DcmTransportConnection *connections[], int connCount, int timeout)
 {
-  int numberOfRounds = timeout+1;
-  if (numberOfRounds < 0) numberOfRounds = 0xFFFF; /* a long time */
-
+  double dtimeout = timeout;
   OFBool found = OFFalse;
-  OFBool firstRound = OFTrue;
-  int timeToWait=0;
+  OFTimer tmr;
   int i=0;
-  while ((numberOfRounds > 0)&&(! found))
+  while ((!found) && (tmr.getDiff() < dtimeout))
   {
-    if (firstRound)
-    {
-      timeToWait = 0;
-      firstRound = OFFalse;
-    }
-    else timeToWait = 1;
     for (i=0; i<connCount; i++)
     {
       if (connections[i])
       {
-        if (connections[i]->networkDataAvailable(timeToWait))
+
+        if (connections[i]->networkDataAvailable(0))
         {
           i = connCount; /* break out of for loop */
           found = OFTrue; /* break out of while loop */
         }
-        timeToWait = 0;
       }
     } /* for */
-    if (timeToWait == 1) return OFFalse; /* all entries NULL */
-    numberOfRounds--;
+    if (!found) OFStandard::milliSleep(10);
   } /* while */
 
-  /* number of rounds == 0 (timeout over), do final check */
+  /* Readable connection found or timeout reached. Do final check. */
   found = OFFalse;
   for (i=0; i<connCount; i++)
   {
@@ -187,6 +175,7 @@ OFBool DcmTransportConnection::safeSelectReadableAssociation(DcmTransportConnect
       if (connections[i]->networkDataAvailable(0)) found = OFTrue; else connections[i]=NULL;
     }
   }
+
   return found;
 }
 
index 0c939956a73a37da717fa6b04c85f1ad4abd8fe0..fa715c9f3c7e2bde3c122d27942b3d7d026fe303 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 #include "dcmtk/dcmnet/diutil.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
 #ifdef HAVE_SYS_UTSNAME_H
 #include <sys/utsname.h>
 #endif
@@ -264,30 +260,6 @@ int dcmtk_flock(int fd, int operation)
 
 #endif /* HAVE_FLOCK */
 
-#ifndef HAVE_ACCESS
-
-/*
-** The access function is OS dependent.
-*/
-
-#if defined(macintosh) || defined(_WIN32)
-int access(const char* path, int /* amode */)
-{
-    int rc;
-    struct stat buf;
-
-    rc = stat(path, &buf);
-
-    /* WARNING
-    ** on the macintosh if a file is there we can do anything with it except
-    ** if it is locked or on a read only filesystem.  Trying to find out about
-    ** that is too complicated at the moment.
-    */
-    return rc;
-}
-#endif
-
-#endif /* HAVE_ACCESS */
 
 DCMTK_DCMNET_EXPORT void dcmtk_plockerr(const char *s)
 {
index 088394a1709b7157e8cdcdd65cf592674f299ccc..1f520282cdf8e94f8622b4413ffcd410cb9910f1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"                /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
index a0165510596675e9fe495e1cebabc63518b125d3..da760ce1d3b7fd533c87388f29dd0c5b5fbe2455 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmdata/dcdatset.h"
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcelem.h"
index 2853573e9068099089d61a3b2d1ee7ba9a19a434..eee10efa022a0d0974c09c0ee0255a717a578a55 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2021, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"         /* always include the module header */
 #include "dcmtk/dcmdata/dcuid.h"
index 53ee40f2c86c924ef0c51d0d933163e17e915d6a..c0c7bef4b36f571cb192b6038c114cd197ab7d55 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"              /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
index 485293ed0bfc52ce9d98eb4d3718bdbe3a42a929..4ee937c00ff874ab213c58b7e7fd7733fb8e3b8d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"              /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
index 5a1b76841086a5b753bc9cf7399c17ce4952b624..79cf1d7f9c16684084858386e015d1d97f664135 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 #include "dcmtk/ofstd/oftimer.h"
-
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"       /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
index 70ed62aa788442b9b42f4f71430f701030470616..38d011ff5abaa2183baf2d603cc1c645af536966 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"        /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
@@ -338,6 +335,7 @@ getTransferSyntax(
 #ifdef WITH_ZLIB
         case EXS_DeflatedLittleEndianExplicit:
 #endif
+        case EXS_DeflatedImageFrameCompression:
         case EXS_JPEGLSLossless:
         case EXS_JPEGLSLossy:
         case EXS_JPEG2000LosslessOnly:
index 6976616dbfc483dcbd2e9b12c59e768878ee5de1..414db2713ea9736dd83565f73b55e40e8b8ff174 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmnet/dimse.h"        /* always include the module header */
 #include "dcmtk/dcmnet/cond.h"
index 3f1b39ffb2814ed1874058f93390b0f7dec86f60..8ced9f23b55eace3d42773de8df104374623c44e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
-
 #include "dcmtk/ofstd/ofstd.h"
 #include "dcmtk/dcmnet/diutil.h"
 #include "dcmtk/dcmdata/dcdatset.h"
index fb1856db4d55bcd42f9f67419308fc574a0aa8e9..36293664494eb269a325750b76974a596a6e68e5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2013-2022, OFFIS e.V.
+ *  Copyright (C) 2013-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -185,6 +185,7 @@ OFCondition DcmStorageSCP::handleIncomingCommand(T_DIMSE_Message *incomingMsg,
         {
             // handle incoming C-ECHO request
             status = handleECHORequest(incomingMsg->msg.CEchoRQ, presInfo.presentationContextID);
+            // TODO: need to handle invalid abstract syntax
         }
         else if (incomingMsg->CommandField == DIMSE_C_STORE_RQ)
         {
index b821b3d2b0031226932214da97696829aeff1c6e..9fba5f02bab7a64dee4db308aaa47ea809844466 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
@@ -83,9 +83,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 /* sys/socket.h included via "dcmtk/ofstd/ofsockad.h" - needed for Ultrix */
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
@@ -103,9 +101,7 @@ BEGIN_EXTERN_C
 #include <tcpd.h>               /* for hosts_ctl */
 int dcmtk_hosts_access(struct request_info *req);
 #endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>              /* for FD_CLOEXEC */
-#endif
 
 /* declare extern "C" typedef for signal handler function pointer */
 typedef void(*mySIG_TYP)(int);
@@ -139,6 +135,7 @@ OFGlobal<DcmNativeSocketType> dcmExternalSocketHandle(DCMNET_INVALID_SOCKET);
 OFGlobal<const char *> dcmTCPWrapperDaemonName((const char *)NULL);
 OFGlobal<unsigned long> dcmEnableBackwardCompatibility(0);
 OFGlobal<size_t> dcmAssociatePDUSizeLimit(0x100000);
+OFGlobal<T_ASC_ProtocolFamily> dcmIncomingProtocolFamily(ASC_AF_Default);
 
 static int networkInitialized = 0;
 
@@ -196,6 +193,7 @@ static OFBool shouldFork = OFFalse;
 #ifdef _WIN32
 static char **command_argv = NULL;
 static int command_argc = 0;
+static DUL_CREATEPROCESS_CALLBACK create_process_callback = NULL;
 #endif
 
 OFBool DUL_processIsForkedChild()
@@ -246,16 +244,18 @@ OFCondition DUL_readSocketHandleAsForkedChild()
 }
 
 
-void DUL_requestForkOnTransportConnectionReceipt(int argc, char *argv[])
+void DUL_requestForkOnTransportConnectionReceipt(int argc, char *argv[], DUL_CREATEPROCESS_CALLBACK cb)
 {
   shouldFork = OFTrue;
 #ifdef _WIN32
   command_argc = argc;
   command_argv = argv;
+  create_process_callback = cb;
 #else
   // Work around "Unused parameters"
   (void) argc;
   (void) argv;
+  (void) cb;
 #endif
 }
 
@@ -1566,7 +1566,7 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
     struct timeval timeout_val;
     socklen_t len;
     int nfound, connected;
-    struct sockaddr from;
+    struct sockaddr_storage from;
     struct linger sockarg;
 
 #ifdef HAVE_FORK
@@ -1590,7 +1590,7 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
       connected = 1;
 
       len = sizeof(from);
-      if (getpeername(sock, &from, &len))
+      if (getpeername(sock, OFreinterpret_cast(struct sockaddr*, &from), &len))
       {
           OFOStringStream stream;
           stream << "TCP Initialization Error: " << OFStandard::getLastNetworkErrorCode().message()
@@ -1695,7 +1695,7 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
         len = sizeof(from);
         do
         {
-            sock = accept((*network)->networkSpecific.TCP.listenSocket, &from, &len);
+            sock = accept((*network)->networkSpecific.TCP.listenSocket, OFreinterpret_cast(struct sockaddr*, &from), &len);
 #ifdef _WIN32
         } while (sock == INVALID_SOCKET && WSAGetLastError() == WSAEINTR);
         if (sock == INVALID_SOCKET)
@@ -1863,7 +1863,18 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
                 // close handles in PROCESS_INFORMATION structure
                 // and our local copy of the socket handle.
                 CloseHandle(hParentProcessHandle);
-                CloseHandle(pi.hProcess);
+
+                if (create_process_callback)
+                {
+                    // hand the process handle over to the callback process.
+                    // The user code is now responsible for closing the handle when not needed anymore.
+                    (*create_process_callback)(pi.hProcess);
+                }
+                else
+                {
+                    CloseHandle(pi.hProcess);
+                }
+
                 CloseHandle(pi.hThread);
                 closesocket(sock);
 
@@ -1915,8 +1926,10 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0)
 #endif
     {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
+        OFOStringStream stream;
+        stream << "TCP Initialization Error: " << OFStandard::getLastNetworkErrorCode().message()
+               << ", setsockopt failed on socket " << sock << OFStringStream_ends;
+        OFSTRINGSTREAM_GETOFSTRING(stream, msg)
         return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
     }
     setTCPBufferLength(sock);
@@ -1959,8 +1972,10 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
 #endif
       if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcpNoDelay, sizeof(tcpNoDelay)) < 0)
       {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
+        OFOStringStream stream;
+        stream << "TCP Initialization Error: " << OFStandard::getLastNetworkErrorCode().message()
+               << ", setsockopt failed on socket " << sock << OFStringStream_ends;
+        OFSTRINGSTREAM_GETOFSTRING(stream, msg)
         return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
       }
 #ifdef DISABLE_NAGLE_ALGORITHM
@@ -1969,28 +1984,49 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
 #endif
     }
 
-    // create string containing numerical IP address.
+
+    // lookup string containing numerical IP address.
     OFString client_dns_name;
-    char client_ip_address[20];
-    OFStandard::snprintf(client_ip_address, sizeof(client_ip_address), "%-d.%-d.%-d.%-d",  // this code is ugly but thread safe
-       ((int) from.sa_data[2]) & 0xff,
-       ((int) from.sa_data[3]) & 0xff,
-       ((int) from.sa_data[4]) & 0xff,
-       ((int) from.sa_data[5]) & 0xff);
+    OFString client_ip_address;
+    char host[NI_MAXHOST]; // buffer for numerical IP address in text form
+    char serv[NI_MAXSERV]; // buffer for port number in text form
+    if (getnameinfo((struct sockaddr*)&from, len,
+                    host, sizeof(host),
+                    serv, sizeof(serv),
+                    NI_NUMERICHOST | NI_NUMERICSERV) == 0)
+    {
+        client_ip_address = host;
+    }
+    else
+    {
+        client_ip_address = "unknown address";
+    }
 
+    // lookup hostname
     if (! dcmDisableGethostbyaddr.get())
-       client_dns_name = OFStandard::getHostnameByAddress(&from.sa_data[2], sizeof(struct in_addr), AF_INET);
+    {
+         struct sockaddr *saddr = OFreinterpret_cast(struct sockaddr*, &from);
+         if (saddr->sa_family == AF_INET6)
+         {
+             client_dns_name = OFStandard::getHostnameByAddress(&saddr->sa_data[6], sizeof(struct in6_addr), AF_INET6);
+         }
+         else if (saddr->sa_family == AF_INET)
+         {
+             client_dns_name = OFStandard::getHostnameByAddress(&saddr->sa_data[2], sizeof(struct in_addr), AF_INET);
+         }
+    }
 
     if (client_dns_name.length() == 0)
     {
         // reverse DNS lookup disabled or host not found, use numerical address
-        OFStandard::strlcpy(params->callingPresentationAddress, client_ip_address,
+        OFStandard::strlcpy(params->callingPresentationAddress, client_ip_address.c_str(),
           sizeof(params->callingPresentationAddress));
-        OFStandard::strlcpy((*association)->remoteNode, client_ip_address, sizeof((*association)->remoteNode));
-        DCMNET_DEBUG("Association Received: " << params->callingPresentationAddress );
+        OFStandard::strlcpy((*association)->remoteNode, client_ip_address.c_str(),
+          sizeof((*association)->remoteNode));
     }
     else
     {
+        // use either full domain name (if DUL_FULLDOMAINNAME is set) or just the hostname
         char node[260];
         if ((*network)->options & DUL_FULLDOMAINNAME)
             OFStandard::strlcpy(node, client_dns_name.c_str(), sizeof(node));
@@ -2000,8 +2036,8 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
         }
         OFStandard::strlcpy((*association)->remoteNode, node, sizeof((*association)->remoteNode));
         OFStandard::strlcpy(params->callingPresentationAddress, node, sizeof(params->callingPresentationAddress));
-        DCMNET_DEBUG("Association Received: " << params->callingPresentationAddress );
     }
+    DCMNET_DEBUG("Association Received: " << params->callingPresentationAddress );
 
 #ifdef WITH_TCPWRAPPER
     const char *daemon = dcmTCPWrapperDaemonName.get();
@@ -2014,7 +2050,7 @@ receiveTransportConnectionTCP(PRIVATE_NETWORKKEY ** network,
 
         struct request_info request;
         request_init(&request, RQ_CLIENT_NAME, client_dns_name.c_str(), 0);
-        request_set(&request, RQ_CLIENT_ADDR, client_ip_address, 0);
+        request_set(&request, RQ_CLIENT_ADDR, client_ip_address.c_str(), 0);
         request_set(&request, RQ_USER, STRING_UNKNOWN, 0);
         request_set(&request, RQ_DAEMON, daemon, 0);
 
@@ -2168,100 +2204,192 @@ initializeNetworkTCP(PRIVATE_NETWORKKEY ** key, void *parameter)
         ((*key)->applicationFunction & DICOM_APPLICATION_ACCEPTOR) &&
         (! processIsForkedChild))
     {
-
-      socklen_t length;
-
 #ifdef _WIN32
-      SOCKET sock;
+        SOCKET sock = INVALID_SOCKET;
 #else
-      int sock;
+        int sock = -1;
 #endif
-      struct sockaddr_in server;
 
-      /* Create socket for Internet type communication */
-      (*key)->networkSpecific.TCP.port = *(int *) parameter;
+        // extract port number from the generic parameter passed to this function
+        (*key)->networkSpecific.TCP.port = *(int *) parameter;
+        int port = (*key)->networkSpecific.TCP.port;
 
-      // Create socket and prevent leakage of the open socket to processes called with exec()
-      // by using SOCK_CLOEXEC (where available) or FD_CLOEXEC (POSIX.1-2008)
+        // determine which protocol family we should support
+        T_ASC_ProtocolFamily supportedFamily = dcmIncomingProtocolFamily.get();
+        int af = 0;
+        switch(supportedFamily)
+        {
+            case ASC_AF_Default:
+              af = AF_INET; // for now the default is to use IPv4 only
+              break;
+            case ASC_AF_INET:
+              af = AF_INET; // IPv4 only
+              break;
+            case ASC_AF_INET6:
+              af = AF_INET6; // IPv6 only
+              break;
+            case ASC_AF_UNSPEC:
+              af = AF_INET6; // IPv6 in dual-stack mode
+              break;
+        }
+
+        // Create socket and prevent leakage of the open socket to processes called with exec()
+        // by using SOCK_CLOEXEC (where available) or FD_CLOEXEC (POSIX.1-2008)
 #ifdef SOCK_CLOEXEC
-      (*key)->networkSpecific.TCP.listenSocket = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
-      sock = (*key)->networkSpecific.TCP.listenSocket;
+        sock = socket(af, SOCK_STREAM | SOCK_CLOEXEC, 0);
 #elif defined(FD_CLOEXEC)
-      (*key)->networkSpecific.TCP.listenSocket = socket(AF_INET, SOCK_STREAM, 0);
-      sock = (*key)->networkSpecific.TCP.listenSocket;
-      if (sock >= 0)
-      {
-          int flags = fcntl(sock, F_GETFD, 0);
-          fcntl(sock, F_SETFD, FD_CLOEXEC | flags);
-      }
+        sock = socket(af, SOCK_STREAM, 0);
+        if (sock >= 0)
+        {
+            int flags = fcntl(sock, F_GETFD, 0);
+            fcntl(sock, F_SETFD, FD_CLOEXEC | flags);
+        }
 #else
-      (*key)->networkSpecific.TCP.listenSocket = socket(AF_INET, SOCK_STREAM, 0);
-      sock = (*key)->networkSpecific.TCP.listenSocket;
+        sock = socket(af, SOCK_STREAM, 0);
 #endif
+#ifdef _WIN32
+        if (sock == INVALID_SOCKET)
+#else
+        if (sock < 0)
+#endif
+        {
+            OFString msg = "TCP Initialization Error: ";
+            msg += OFStandard::getLastNetworkErrorCode().message();
+            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+        }
+
+        // store socket handle
+        (*key)->networkSpecific.TCP.listenSocket = sock;
 
+        // make sure that no other process is already bound to the same port.
+        // In this case we want bind() to fail.
 #ifdef _WIN32
-      if (sock == INVALID_SOCKET)
+        if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &reuse, sizeof(reuse)) < 0)
 #else
-      if (sock < 0)
+        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0)
 #endif
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
-      reuse = 1;
+        {
 #ifdef _WIN32
-      if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &reuse, sizeof(reuse)) < 0)
+            (void) shutdown(sock,  1 /* SD_SEND */);
+            closesocket(sock);
+            (*key)->networkSpecific.TCP.listenSocket = INVALID_SOCKET;
 #else
-      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0)
+            close(sock);
+            (*key)->networkSpecific.TCP.listenSocket = -1;
 #endif
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-          return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
+            OFString msg = "TCP Initialization Error: ";
+            msg += OFStandard::getLastNetworkErrorCode().message();
+            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+        }
 
-      /* Name socket using wildcards */
-      server.sin_family = AF_INET;
-      server.sin_addr.s_addr = INADDR_ANY;
-      server.sin_port = htons(OFstatic_cast(Uint16, ((*key)->networkSpecific.TCP.port)));
-      if (bind(sock, (struct sockaddr *) & server, sizeof(server)))
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
-      /* Find out assigned port number and print it out */
-      length = sizeof(server);
-      if (getsockname(sock, (struct sockaddr *) &server, &length))
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
+        // configure the IPv6 socket either as IPv6 only or as a dual stack socket
+        // that accepts IPv4 via v4-mapped
+        if (af == AF_INET6)
+        {
+            int off = (supportedFamily == ASC_AF_UNSPEC) ? 0 : 1;
+            if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off)))
+            {
+#ifdef _WIN32
+                (void) shutdown(sock,  1 /* SD_SEND */);
+                closesocket(sock);
+                (*key)->networkSpecific.TCP.listenSocket = INVALID_SOCKET;
+#else
+                close(sock);
+                (*key)->networkSpecific.TCP.listenSocket = -1;
+#endif
+                OFString msg = "TCP Initialization Error: ";
+                msg += OFStandard::getLastNetworkErrorCode().message();
+                return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+            }
+        }
 
-      /* If port 0 was specified by the client, the OS has assigned an unused port. */
-      if ((*key)->networkSpecific.TCP.port == 0) {
-        const u_short assignedPort = ntohs(server.sin_port);
-        (*key)->networkSpecific.TCP.port = assignedPort;
-        *(int *) parameter = assignedPort;
-      }
+        // bind the socket to the given port number
+        OFBool bind_ok = OFFalse;
+        if (af == AF_INET6) {
+            struct sockaddr_in6 server6;
+            memset(&server6, 0, sizeof(server6));
+            server6.sin6_family = AF_INET6;
+            server6.sin6_addr = in6addr_any;
+            server6.sin6_port = htons(OFstatic_cast(Uint16, port));
+            if (bind(sock, (struct sockaddr *)&server6, sizeof(server6)) == 0) bind_ok = OFTrue;
+        } else if (af == AF_INET) {
+            struct sockaddr_in server;
+            memset(&server, 0, sizeof(server));
+            server.sin_family = AF_INET;
+            server.sin_addr.s_addr = INADDR_ANY;
+            server.sin_port = htons(OFstatic_cast(Uint16, port));
+            if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == 0) bind_ok = OFTrue;
+        }
 
-      sockarg.l_onoff = 0;
-      if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &sockarg, sizeof(sockarg)) < 0)
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
+        if (! bind_ok) {
+#ifdef _WIN32
+            (void) shutdown(sock,  1 /* SD_SEND */);
+            closesocket(sock);
+            (*key)->networkSpecific.TCP.listenSocket = INVALID_SOCKET;
+#else
+            close(sock);
+           (*key)->networkSpecific.TCP.listenSocket = -1;
+#endif
+           OFString msg = "TCP Initialization Error: ";
+           msg += OFStandard::getLastNetworkErrorCode().message();
+           return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+       }
+
+       // disable linger mode, i.e. when closing the socket,
+       // do not wait until all queued messages for the socket have been
+       // successfully sent or the linger timeout has been reached.
+       sockarg.l_onoff = 0;
+       if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &sockarg, sizeof(sockarg)) < 0)
+       {
+#ifdef _WIN32
+           (void) shutdown(sock,  1 /* SD_SEND */);
+            closesocket(sock);
+            (*key)->networkSpecific.TCP.listenSocket = INVALID_SOCKET;
+#else
+            close(sock);
+            (*key)->networkSpecific.TCP.listenSocket = -1;
+#endif
+            OFString msg = "TCP Initialization Error: ";
+            msg += OFStandard::getLastNetworkErrorCode().message();
+            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+        }
 
-      /* Listen on the socket */
-      if (listen(sock, PRV_LISTENBACKLOG) < 0)
-      {
-        OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
-        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
-      }
+        // listen for incoming connections, limit backlog to at most
+        // PRV_LISTENBACKLOG (i.e. 50) incoming connection request
+        if (listen(sock, PRV_LISTENBACKLOG) < 0)
+        {
+#ifdef _WIN32
+            (void) shutdown(sock,  1 /* SD_SEND */);
+            closesocket(sock);
+            (*key)->networkSpecific.TCP.listenSocket = INVALID_SOCKET;
+#else
+            close(sock);
+            (*key)->networkSpecific.TCP.listenSocket = -1;
+#endif
+            OFString msg = "TCP Initialization Error: ";
+            msg += OFStandard::getLastNetworkErrorCode().message();
+            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
+        }
+
+        // If port 0 was specified by the caller, the OS has assigned an unused port.
+        // store this port and return it in the parameter passed to this function
+        if (port == 0)
+        {
+            if (af == AF_INET6)
+            {
+                struct sockaddr_in6 sin6; socklen_t sl = sizeof(sin6);
+                if (getsockname(sock, (struct sockaddr *)&sin6, &sl) == 0)
+                    port = ntohs(sin6.sin6_port);
+            }
+            else
+            {
+                struct sockaddr_in sin; socklen_t sl = sizeof(sin);
+                if (getsockname(sock, (struct sockaddr *)&sin, &sl) == 0)
+                    port = ntohs(sin.sin_port);
+            }
+            (*key)->networkSpecific.TCP.port = port;
+            *(int *) parameter = port;
+        }
     }
 
     (*key)->networkSpecific.TCP.tLayer = new DcmTransportLayer();
index 2b52471b4588465675d1375ebb873aba3a32fed1..a32c5ca61412e25141b113ab2497c8f6d5e3bbf3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
@@ -82,9 +82,7 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -147,7 +145,7 @@ DUL_associationWaiting(DUL_NETWORKKEY * callerNet, int timeout)
     t.tv_sec = timeout;
     t.tv_usec = 0;
 #ifdef DCMTK_HAVE_POLL
-    struct pollfd pfd[] = 
+    struct pollfd pfd[] =
     {
        { s, POLLIN, 0 }
     };
index c9ba5e61cf05a42c118d393ebd0d9e39c0061da0..060361eccfb7478521402b3ea4bcaf93afa399b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1994-2024, OFFIS e.V.
+ *  Copyright (C) 1994-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were partly developed by
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
-#endif
 
 BEGIN_EXTERN_C
 #ifdef HAVE_NETINET_IN_SYSTM_H
@@ -2463,9 +2459,8 @@ requestAssociationTCP(PRIVATE_NETWORKKEY ** network,
                 if ((*association)->connection) delete (*association)->connection;
                 (*association)->connection = NULL;
 
-                char buf[256];
                 OFString msg = "TCP Initialization Error: ";
-                msg += OFStandard::strerror(socketError, buf, sizeof(buf));
+                msg += OFStandard::getLastNetworkErrorCode().message();
                 return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
             }
         }
@@ -2490,6 +2485,7 @@ requestAssociationTCP(PRIVATE_NETWORKKEY ** network,
     {
         // an error other than timeout in non-blocking mode has occurred,
         // either in connect() or in select().
+        OFerror_code ec = OFStandard::getLastNetworkErrorCode();
 #ifdef HAVE_WINSOCK_H
         (void) shutdown(s,  1 /* SD_SEND */);
         (void) closesocket(s);
@@ -2501,7 +2497,7 @@ requestAssociationTCP(PRIVATE_NETWORKKEY ** network,
         (*association)->connection = NULL;
 
         OFString msg = "TCP Initialization Error: ";
-        msg += OFStandard::getLastNetworkErrorCode().message();
+        msg += ec.message();
         return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
     } else {
         // success - we've opened a TCP transport connection
@@ -3550,7 +3546,7 @@ readPDUHeadTCP(PRIVATE_ASSOCIATIONKEY ** association,
     if (!found)
     {
         char buf[256];
-        OFStandard::snprintf(buf, sizeof(buf), "Unrecognized PDU type: %2x", *type);
+        OFStandard::snprintf(buf, sizeof(buf), "Unrecognized PDU type: %2.2x", *type);
         return makeDcmnetCondition(DULC_UNRECOGNIZEDPDUTYPE, OF_error, buf);
     }
 
index eb4aef99084e3147d069aa16182d157cb8ce06b1..0b84d00bac3c7a27a087edb3b0b77b88b5b217c1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2009-2024, OFFIS e.V.
+ *  Copyright (C) 2009-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -386,14 +386,16 @@ OFCondition DcmSCP::waitForAssociationRQ(T_ASC_Network* network)
     OFBool useSecureLayer = m_cfg->transportLayerEnabled();
 
     // Listen to a socket for timeout seconds and wait for an association request
-    OFCondition cond = ASC_receiveAssociation(network,
-                                              &m_assoc,
-                                              m_cfg->getMaxReceivePDULength(),
-                                              NULL,
-                                              NULL,
-                                              useSecureLayer,
-                                              m_cfg->getConnectionBlockingMode(),
-                                              OFstatic_cast(int, timeout));
+    OFCondition cond = ASC_receiveAssociation(
+        network,
+        &m_assoc,
+        m_cfg->getMaxReceivePDULength(),
+        NULL,
+        NULL,
+        useSecureLayer,
+        m_cfg->getConnectionBlockingMode(),
+        OFstatic_cast(int, timeout),
+        m_cfg->getImplementationIdentification());
 
     // In case of a timeout in non-blocking mode, call notifier (and return
     // to main event loop later)
index f057d55ea1cc397e0367dcfaeb42d8029c7c8f24..8863175906ff30214fc814dbf0cae780e624ad6a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2024, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -28,6 +28,7 @@
 DcmSCPConfig::DcmSCPConfig() :
   m_assocConfig(),
   m_assocCfgProfileName("DEFAULT"),
+  m_implIdentification(),
   m_port(104),
   m_aetitle("DCMTK_SCP"),
   m_refuseAssociation(OFFalse),
@@ -56,6 +57,7 @@ DcmSCPConfig::~DcmSCPConfig()
 DcmSCPConfig::DcmSCPConfig(const DcmSCPConfig &old) :
   m_assocConfig(old.m_assocConfig),
   m_assocCfgProfileName(old.m_assocCfgProfileName),
+  m_implIdentification(old.m_implIdentification),
   m_port(old.m_port),
   m_aetitle(old.m_aetitle),
   m_refuseAssociation(old.m_refuseAssociation),
@@ -82,6 +84,7 @@ DcmSCPConfig& DcmSCPConfig::operator=(const DcmSCPConfig &obj)
   {
     m_assocConfig = obj.m_assocConfig; // performs deep copy
     m_assocCfgProfileName = obj.m_assocCfgProfileName;
+    m_implIdentification = obj.m_implIdentification;
     m_port = obj.m_port;
     m_aetitle = obj.m_aetitle;
     m_refuseAssociation = obj.m_refuseAssociation;
@@ -401,6 +404,18 @@ OFCondition DcmSCPConfig::checkAssociationProfile(const OFString& profileName,
 }
 
 
+void DcmSCPConfig::setImplementationIdentification(const T_ASC_ImplementationIdentification& implIdentification)
+{
+    m_implIdentification = implIdentification;
+}
+
+
+const T_ASC_ImplementationIdentification& DcmSCPConfig::getImplementationIdentification() const
+{
+    return m_implIdentification;
+}
+
+
 OFCondition DcmSCPConfig::addPresentationContext(const OFString &abstractSyntax,
                                                  const OFList<OFString> &xferSyntaxes,
                                                  const T_ASC_SC_ROLE role,
index a134065d0eecc5a3e153ac35ed379c4948dc8d03..c4a5d61fa31ad31199cd97aa9442904ae8eb035a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2020, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -38,7 +38,7 @@ DcmBaseSCPPool::DcmBaseSCPPool()
     m_workersIdle(),
     m_cfg(),
     m_maxWorkers(5),
-    m_runMode( LISTEN )
+    m_runMode( SHUTDOWN ) // LISTEN mode will be set, once actual listening will be started.
     // not implemented yet: m_workersBusyTimeout(60),
     // not implemented yet: m_waiting(),
 {
@@ -48,6 +48,27 @@ DcmBaseSCPPool::DcmBaseSCPPool()
 
 DcmBaseSCPPool::~DcmBaseSCPPool()
 {
+  // Wait that we are in SHUTDOWN mode
+  // Let busy threads finish their work and get moved from the busy list to the idle list.
+  while (m_runMode != SHUTDOWN || DcmBaseSCPPool::numThreads(OFTrue) != 0)
+  {
+    DCMNET_DEBUG("DcmBaseSCPPool: Destructor called, waiting for runMode to become SHUTDOWN (currently " << m_runMode << ")");
+    OFStandard::forceSleep(1);
+  }
+  DCMNET_DEBUG("DcmBaseSCPPool: Destructor called, cleaning up " << m_workersIdle.size() << " idle worker threads");
+  // Now all workers must be in idle list which will be joined and deleted now.
+  // Since we are in SHUTDOWN mode, no other thread can modify the lists anymore.
+  m_criticalSection.lock();
+  size_t count = 1;
+  for (OFListIterator(DcmBaseSCPWorker*) it = m_workersIdle.begin(); it != m_workersIdle.end(); ++it)
+  {
+    DCMNET_DEBUG("DcmBaseSCPPool: Joining and deleting idle worker thread " << count << ", #" << (*it)->threadID());
+    (*it)->join();
+    delete (*it);
+    count++;
+  }
+  m_criticalSection.unlock();
+  DCMNET_DEBUG("DcmBaseSCPPool: Destructor finished");
 }
 
 // ----------------------------------------------------------------------------
@@ -61,9 +82,12 @@ OFCondition DcmBaseSCPPool::listen()
 
   /* Initialize network, i.e. create an instance of T_ASC_Network*. */
   T_ASC_Network *network = NULL;
-  OFCondition cond = initializeNework(&network);
+  OFCondition cond = initializeNetwork(&network);
   if(cond.bad())
+  {
+    finishListening();
     return cond;
+  }
 
   /* As long as all is fine (or we have been to busy handling last connection request) keep listening */
   while ( m_runMode == LISTEN && ( cond.good() || (cond == NET_EC_SCPBusy) ) )
@@ -75,8 +99,16 @@ OFCondition DcmBaseSCPPool::listen()
     OFBool useSecureLayer = m_cfg.transportLayerEnabled();
 
     // Listen to a socket for timeout seconds for an association request, accepts TCP connection.
-    cond = ASC_receiveAssociation( network, &assoc, m_cfg.getMaxReceivePDULength(), NULL, NULL, useSecureLayer,
-        m_cfg.getConnectionBlockingMode(), OFstatic_cast(int, m_cfg.getConnectionTimeout()) );
+    cond = ASC_receiveAssociation(
+        network,
+        &assoc,
+        m_cfg.getMaxReceivePDULength(),
+        NULL,
+        NULL,
+        useSecureLayer,
+        m_cfg.getConnectionBlockingMode(),
+        OFstatic_cast(int, m_cfg.getConnectionTimeout()),
+        m_cfg.getImplementationIdentification());
 
     /* If we have a connection request, try to find/create a worker to handle it */
     if (cond.good())
@@ -115,26 +147,17 @@ OFCondition DcmBaseSCPPool::listen()
       cond = EC_Normal;
     }
   }
+  // Log why we left the listen loop
+  if (cond.bad())
+    DCMNET_DEBUG("DcmBaseSCPPool: Leaving listen loop due to error: " << cond.text());
+  else if (cond == NET_EC_SCPBusy)
+    DCMNET_DEBUG("DcmBaseSCPPool: Leaving listen loop due to too many concurrent connections (busy).");
+  else if (m_runMode == STOP)
+    DCMNET_DEBUG("DcmBaseSCPPool: Leaving listen loop due to stop request.");
+  else
+    DCMNET_DEBUG("DcmBaseSCPPool: Leaving listen loop, result: " << cond.text() << " (runMode: " << m_runMode << ")");
 
-  m_criticalSection.lock();
-  m_runMode = SHUTDOWN;
-
-  // iterate over all busy workers, join their threads and delete them.
-  for
-  (
-    OFListIterator( DcmBaseSCPPool::DcmBaseSCPWorker* ) it = m_workersBusy.begin();
-    it != m_workersBusy.end();
-    ++it
-  )
-  {
-    m_criticalSection.unlock();
-    (*it)->join();
-    delete *it;
-    m_criticalSection.lock();
-  }
-
-  m_workersBusy.clear();
-  m_criticalSection.unlock();
+  finishListening();
 
   /* In the end, clean up the rest of the memory and drop network */
   ASC_dropNetwork(&network);
@@ -188,6 +211,7 @@ OFCondition DcmBaseSCPPool::runAssociation(T_ASC_Association *assoc,
   /* Try to find idle worker thread */
   OFCondition result = EC_Normal;
   DcmBaseSCPWorker *chosen = NULL;
+  OFBool isNewWorker = OFFalse;
 
   /* Do we have idle worker threads that can handle the association? */
   m_criticalSection.lock();
@@ -195,6 +219,7 @@ OFCondition DcmBaseSCPPool::runAssociation(T_ASC_Association *assoc,
   {
     if (m_workersBusy.size() >= m_maxWorkers)
     {
+      DCMNET_DEBUG("DcmBaseSCPPool: Maximum number of busy worker threads reached (" << m_maxWorkers << "), cannot handle incoming association");
       /* No idle workers and maximum of busy workers reached? Return busy */
       result = NET_EC_SCPBusy;
     }
@@ -211,12 +236,15 @@ OFCondition DcmBaseSCPPool::runAssociation(T_ASC_Association *assoc,
         m_workersBusy.push_back(worker);
         worker->setSharedConfig(sharedConfig);
         chosen = worker;
+        isNewWorker = OFTrue;
+        DCMNET_DEBUG("DcmBaseSCPPool: Created new worker thread, now " << m_workersBusy.size() << " busy threads total");
       }
     }
   }
   /* Else we have idle workers, use one of them */
   else
   {
+    DCMNET_DEBUG("DcmBaseSCPPool: Reusing existing idle DcmSCP worker thread #" << m_workersIdle.front()->threadID());
     chosen = m_workersIdle.front();
     m_workersIdle.pop_front();
     m_workersBusy.push_back(chosen);
@@ -230,13 +258,19 @@ OFCondition DcmBaseSCPPool::runAssociation(T_ASC_Association *assoc,
     result = chosen->setAssociation(assoc);
   }
   /* Start the thread */
-  if (result.good())
+  if (isNewWorker && result.good())
   {
      if (chosen->start() != 0)
      {
        result = NET_EC_CannotStartSCPThread;
      }
   }
+  else if (result.good())
+  {
+    // If we reuse an existing worker thread, it might be waiting for an association.
+    // Wake it up now.
+    chosen->rerun();
+  }
   /* Return to listen loop */
   return result;
 }
@@ -274,23 +308,29 @@ DcmSCPConfig& DcmBaseSCPPool::getConfig()
 
 // ----------------------------------------------------------------------------
 
-void DcmBaseSCPPool::notifyThreadExit(DcmBaseSCPPool::DcmBaseSCPWorker* thread,
+void DcmBaseSCPPool::notifyWorkerDone(DcmBaseSCPPool::DcmBaseSCPWorker* thread,
                                       OFCondition result)
 {
   m_criticalSection.lock();
-  if( m_runMode != SHUTDOWN )
+  if (result.bad())
   {
     DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << thread->threadID() << " exited with error: " << result.text());
-    m_workersBusy.remove(thread);
-    delete thread;
-    thread = NULL;
   }
+  else
+  {
+    DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << thread->threadID() << " finished successfully.");
+  }
+  // Move thread from busy to idle lists
+  m_workersBusy.remove(thread);
+  m_workersIdle.push_back(thread);
+  DCMNET_DEBUG("DcmBaseSCPPool: Put worker thread #" << thread->threadID() << " back to idle list; now "
+              << m_workersBusy.size() << " busy and " << m_workersIdle.size() << " idle worker threads.");
   m_criticalSection.unlock();
 }
 
 // ----------------------------------------------------------------------------
 
-OFCondition DcmBaseSCPPool::initializeNework(T_ASC_Network** network)
+OFCondition DcmBaseSCPPool::initializeNetwork(T_ASC_Network** network)
 {
     OFCondition cond = ASC_initializeNetwork(NET_ACCEPTOR, OFstatic_cast(int, m_cfg.getPort()), m_cfg.getACSETimeout(), network);
     if (cond.good())
@@ -308,6 +348,7 @@ OFCondition DcmBaseSCPPool::initializeNework(T_ASC_Network** network)
     return cond;
 }
 
+
 /* *********************************************************************** */
 /*                        DcmBaseSCPPool::BaseSCPWorker class              */
 /* *********************************************************************** */
@@ -322,7 +363,6 @@ DcmBaseSCPPool::DcmBaseSCPWorker::DcmBaseSCPWorker(DcmBaseSCPPool& pool)
 
 DcmBaseSCPPool::DcmBaseSCPWorker::~DcmBaseSCPWorker()
 {
-  // do nothing
 }
 
 // ----------------------------------------------------------------------------
@@ -330,7 +370,10 @@ DcmBaseSCPPool::DcmBaseSCPWorker::~DcmBaseSCPWorker()
 OFCondition DcmBaseSCPPool::DcmBaseSCPWorker::setAssociation(T_ASC_Association* assoc)
 {
   if (busy())
+  {
+    DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << threadID() << " is already busy, cannot set new association");
     return NET_EC_AlreadyConnected;
+  }
 
   if ( (m_assoc != NULL) || (assoc == NULL) )
     return DIMSE_ILLEGALASSOCIATION;
@@ -347,18 +390,17 @@ void DcmBaseSCPPool::DcmBaseSCPWorker::run()
   if(!m_assoc)
   {
     DCMNET_ERROR("DcmBaseSCPPool: Worker thread #" << threadID() << " received run command but has no association, exiting");
-    m_pool.notifyThreadExit(this, ASC_NULLKEY);
-    thread_exit();
+    m_pool.notifyWorkerDone(this, ASC_NULLKEY);
   }
   else
   {
     T_ASC_Association *param = m_assoc;
     m_assoc = NULL;
     result = workerListen(param);
-    DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << threadID() << " returns with code: " << result.text() );
+    m_pool.notifyWorkerDone(this, result);
+    DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << threadID() << " finished handling association, dropping and destroying its association");
+    DCMNET_DEBUG("DcmBaseSCPPool: Worker thread #" << threadID() << " returns with result: " << result.text() );
   }
-  m_pool.notifyThreadExit(this, result);
-  thread_exit();
   return;
 }
 
@@ -369,4 +411,22 @@ void DcmBaseSCPPool::DcmBaseSCPWorker::exit()
   thread_exit();
 }
 
+// ----------------------------------------------------------------------------
+
+void DcmBaseSCPPool::DcmBaseSCPWorker::rerun()
+{
+  DcmBaseSCPPool::DcmBaseSCPWorker::run();
+}
+
+// ----------------------------------------------------------------------------
+
+void DcmBaseSCPPool::finishListening()
+{
+  m_criticalSection.lock();
+  // Set run mode to SHUTDOWN which signals destructor that its time to clean up
+  m_runMode = SHUTDOWN;
+  m_criticalSection.unlock();
+}
+
+
 #endif // WITH_THREADS
index a6a2e61f484d50991a48487e6d2235f66033ac65..a63d564b0489caf933938adc269c9c13cda130c7 100644 (file)
@@ -57,6 +57,11 @@ OFCondition DcmThreadSCP::setSharedConfig(const DcmSharedSCPConfig& config)
   return EC_Normal;
 }
 
+void DcmThreadSCP::dropAndDestroyAssociation()
+{
+  DcmSCP::dropAndDestroyAssociation();
+}
+
 // ----------------------------------------------------------------------------
 
 OFCondition DcmThreadSCP::run(T_ASC_Association* incomingAssoc)
index 31d93c11e2cc883913309c3c624ec9decb98722a..fa3a863509a2aa75af777522bf1161c1beed0801 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2008-2024, OFFIS e.V.
+ *  Copyright (C) 2008-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -124,7 +124,7 @@ OFCondition DcmSCU::initNetwork()
     }
 
     /* initialize association parameters, i.e. create an instance of T_ASC_Parameters*. */
-    cond = ASC_createAssociationParameters(&m_params, m_maxReceivePDULength, m_tcpConnectTimeout);
+    cond = ASC_createAssociationParameters(&m_params, m_maxReceivePDULength, m_tcpConnectTimeout, m_implIdentification);
     if (cond.bad())
     {
         DCMNET_ERROR(DimseCondition::dump(tempStr, cond));
@@ -2577,6 +2577,11 @@ void DcmSCU::setAssocConfigFileAndProfile(const OFString& filename, const OFStri
     m_assocConfigProfile  = profile;
 }
 
+void DcmSCU::setImplementationIdentification(const T_ASC_ImplementationIdentification& implIdentification)
+{
+    m_implIdentification = implIdentification;
+}
+
 void DcmSCU::setStorageDir(const OFString& storeDir)
 {
     m_storageDir = storeDir;
index b52036fe348626ae02314fb7f2f4789781a008b1..ff3c15ef72f7321579491fb2ac359c23fbbda0c4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2013-2014, OFFIS e.V.
+ *  Copyright (C) 2013-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/ofstd/oftest.h"
 #include "dcmtk/dcmnet/scppool.h"
 #include "dcmtk/dcmnet/scu.h"
+#include "dcmtk/ofstd/ofthread.h"
+
+
+const size_t NUM_THREADS = 20;
 
 struct TestSCU : DcmSCU, OFThread
 {
-    OFCondition result;
+
+    TestSCU() : m_result()
+    {
+        m_resultMutex.lock();
+        m_result = EC_IllegalCall;
+        m_resultMutex.unlock();
+    }
+
+    void getResult(OFCondition& result)
+    {
+        m_resultMutex.lock();
+        result = m_result;
+        m_resultMutex.unlock();
+    }
+
 protected:
+
     void run()
     {
         negotiateAssociation();
-        result = sendECHORequest(0);
+        m_resultMutex.lock();
+        m_result = sendECHORequest(0);
+        m_resultMutex.unlock();
         releaseAssociation();
     }
+
+private:
+
+    OFCondition m_result;
+    OFMutex m_resultMutex;
+
 };
 
 struct TestPool : DcmSCPPool<>, OFThread
@@ -69,7 +96,7 @@ OFTEST_FLAGS(dcmnet_scp_pool, EF_Slow)
     // stopAfterCurrentAssociations().
     config.setConnectionTimeout(1);
 
-    pool.setMaxThreads(20);
+    pool.setMaxThreads(NUM_THREADS);
     OFList<OFString> xfers;
     xfers.push_back(UID_LittleEndianExplicitTransferSyntax);
     xfers.push_back(UID_LittleEndianImplicitTransferSyntax);
@@ -77,7 +104,7 @@ OFTEST_FLAGS(dcmnet_scp_pool, EF_Slow)
 
     pool.start();
 
-    OFVector<TestSCU*> scus(20);
+    OFVector<TestSCU*> scus(NUM_THREADS, NULL);
     for (OFVector<TestSCU*>::iterator it1 = scus.begin(); it1 != scus.end(); ++it1)
     {
         *it1 = new TestSCU;
@@ -91,17 +118,48 @@ OFTEST_FLAGS(dcmnet_scp_pool, EF_Slow)
 
     // "ensure" the pool is initialized before any SCU starts connecting to it. The initialization
     // can take a couple of seconds on older systems, e.g. debian i368.
-    OFStandard::sleep(5);
+    OFStandard::forceSleep(5);
 
     for (OFVector<TestSCU*>::const_iterator it2 = scus.begin(); it2 != scus.end(); ++it2)
         (*it2)->start();
+    // Ensure the SCUs have time to connect and send requests also on slow systems
+    OFStandard::forceSleep(5);
 
     for (OFVector<TestSCU*>::iterator it3 = scus.begin(); it3 != scus.end(); ++it3)
     {
+        OFCondition scuResult;
+        (*it3)->getResult(scuResult);
         (*it3)->join();
-        OFCHECK((*it3)->result.good());
         delete *it3;
+        (*it3) = NULL;
+        OFCHECK(scuResult.good());
     }
+    scus.clear();
+
+    // Second round to check whether thread re-use works inside the pool
+    for (OFVector<TestSCU*>::iterator it4 = scus.begin(); it4 != scus.end(); ++it4)
+    {
+        *it4 = new TestSCU;
+        (*it4)->setAETitle("PoolTestSCU");
+        (*it4)->setPeerAETitle("PoolTestSCP");
+        (*it4)->setPeerHostName("localhost");
+        (*it4)->setPeerPort(11112);
+        (*it4)->addPresentationContext(UID_VerificationSOPClass, xfers);
+        (*it4)->initNetwork();
+    }
+
+    for (OFVector<TestSCU*>::const_iterator it2 = scus.begin(); it2 != scus.end(); ++it2)
+        (*it2)->start();
+
+    for (OFVector<TestSCU*>::iterator it3 = scus.begin(); it3 != scus.end(); ++it3)
+    {
+        OFCondition scuResult;
+        (*it3)->getResult(scuResult);
+        OFCHECK(scuResult.good());
+        (*it3)->join();
+        delete *it3;
+    }
+
 
     // Request shutdown.
     pool.stopAfterCurrentAssociations();
index 3df1e1aae9b12fa1aa4574419aa43ccb8842ddbd..e96dcb35df04e10511ccfed9c8caa4c129c092cb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2024, Open Connections GmbH
+ *  Copyright (C) 2018-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -177,6 +177,35 @@ public:
    */
   virtual OFCondition write(DcmItem &dataset);
 
+    /** If enabled, functional group structure is checked before actual writing
+     *  is performed in the write() method. Checking might be time consuming
+     *  on functional groups with many frames, though disabling might result in
+     *  invalid functional group structures. Disabling should only be done if the
+     *  user knows that the functional groups are valid, wants to to adapt the
+     *  functional groups manually after calling write() or knows what he's doing
+     *  otherwise.<br>
+     *  Per default, checking is enabled.
+     *  @param  doCheck If OFTrue, checking will be performed. If OFFalse,
+     *          no checks are performed.
+     */
+    virtual void setCheckFGOnWrite(const OFBool doCheck);
+
+    /** Returns whether functional group structure is checked before actual
+     *  writing is performed in the write() method.
+     *  @return OFTrue if checking is performed, OFFalse otherwise
+     */
+    virtual OFBool getCheckFGOnWrite();
+
+    /** Set whether attribute values should be checked on writing, i.e. if writing
+     *  should fail if attribute values violate their VR, VM, character set or value length.
+     *  A missing but required value is always considered an error, independent of this setting.
+     *  If set to OFFalse, writing will always succeed, even if attribute value constraints
+     *  are violated. A warning instead of an error will be printed to the logger.
+     *  @param  doCheck If OFTrue, attribute value errors are handled as errors on writing, if OFFalse
+     *          any errors are ignored.
+     */
+    virtual void setValueCheckOnWrite(const OFBool doCheck);
+
   // -------------------- access ---------------------
 
   /** Get Recognizable Visual Features
@@ -298,7 +327,7 @@ private:
   ContentIdentificationMacro m_ContentIdentification;
 
   /// Binary frame data
-  OFVector<DcmIODTypes::Frame*> m_Frames;
+  OFVector<DcmIODTypes::FrameBase*> m_Frames;
 
 };
 
index bc9e4670bb670eb3dc0a03e9b11eec98e8022655..82bd6e2603342f328d8e2a8b08a5159ca4f6fefc 100644 (file)
@@ -69,6 +69,7 @@ dpmmodparametricmapimage.o: dpmmodparametricmapimage.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -146,6 +147,7 @@ dpmmodparametricmapseries.o: dpmmodparametricmapseries.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -225,6 +227,7 @@ dpmparametricmapbase.o: dpmparametricmapbase.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -349,6 +352,7 @@ dpmparametricmapiod.o: dpmparametricmapiod.cc \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
index 9301e3faa7d6580f9ecd892d8ffc836494565565..4dbf315f0aa17db63c62fe3313630dd6b75ae6a6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -149,12 +149,10 @@ struct DPMParametricMapIOD::ReadVisitor
       {
         for (Uint32 n = 0; n < numFrames; n++)
         {
-          DcmIODTypes::Frame* f = new DcmIODTypes::Frame;
+          DcmIODTypes::Frame<T>* f = new DcmIODTypes::Frame<T>(numBytesFrame);
           if (f)
           {
-            f->length = numBytesFrame;
-            f->pixData = new Uint8[f->length];
-            memcpy(f->pixData, pixData + n*numBytesFrame/2, numBytesFrame);
+            memcpy(f->m_pixData, pixData + n*numBytesFrame/2, numBytesFrame);
             map.m_Frames.push_back(f);
           }
           else
@@ -191,12 +189,10 @@ struct DPMParametricMapIOD::ReadVisitor
       {
         for (Uint32 n=0; n < numFrames; n++)
         {
-          DcmIODTypes::Frame* f = new DcmIODTypes::Frame;
-          if (f)
+          DcmIODTypes::Frame<Float32>* f = new DcmIODTypes::Frame<Float32>(numBytesFrame);
+          if (f && f->m_pixData)
           {
-            f->length = numBytesFrame;
-            f->pixData = new Uint8[f->length];
-            memcpy(f->pixData, pixData + n*numBytesFrame/4, numBytesFrame);
+            memcpy(f->m_pixData, pixData + n*numBytesFrame/4, numBytesFrame);
             map.m_Frames.push_back(f);
           }
           else
@@ -233,12 +229,10 @@ struct DPMParametricMapIOD::ReadVisitor
       {
         for (Uint16 n=0; n < numFrames; n++)
         {
-          DcmIODTypes::Frame* f = new DcmIODTypes::Frame;
-          if (f)
+          DcmIODTypes::Frame<Float64>* f = new DcmIODTypes::Frame<Float64>(numBytesFrame);
+          if (f && f->m_pixData)
           {
-            f->length = numBytesFrame;
-            f->pixData = new Uint8[f->length];
-            memcpy(f->pixData, pixData + n*numBytesFrame/8, numBytesFrame);
+            memcpy(f->m_pixData, pixData + n*numBytesFrame/8, numBytesFrame);
             map.m_Frames.push_back(f);
           }
           else
@@ -309,7 +303,7 @@ struct DPMParametricMapIOD::WriteVisitor
     map.getRows(rows);
     map.getColumns(cols);
     const size_t numFrames = map.m_Frames.size();
-    const size_t numBytesFrame = map.m_Frames[0]->length;
+    const size_t numBytesFrame = map.m_Frames[0]->getLengthInBytes();
     const size_t numPixelsFrame = rows * cols;
     // Creates the correct pixel data element, based on the image pixel module used.
     // I.e. For integer data, the "Pixel Data" element is used, i.e. the DcmElement type
@@ -322,7 +316,7 @@ struct DPMParametricMapIOD::WriteVisitor
     {
       for (size_t f = 0; f < numFrames; ++f)
       {
-        memcpy(ptr, map.m_Frames[f]->pixData, numBytesFrame);
+        memcpy(ptr, map.m_Frames[f]->getPixelData(), numBytesFrame);
         ptr += numPixelsFrame;
       }
       OFCondition result = element.put(item);
@@ -591,12 +585,10 @@ OFCondition DPMParametricMapIOD::Frames<PixelType>::addFrame(PixelType* data,
   {
     if (!perFrameInformation.empty())
     {
-      OFunique_ptr<DcmIODTypes::Frame> f(new DcmIODTypes::Frame);
+      OFunique_ptr<DcmIODTypes::Frame<PixelType> > f(new DcmIODTypes::Frame<PixelType>(numPixels * sizeof(PixelType)));
       if (f)
       {
-        f->length = numPixels * sizeof(PixelType);
-        f->pixData = new Uint8[f->length];
-        memcpy(f->pixData, data, f->length);
+        memcpy(f->m_pixData, data, f->getLengthInBytes());
         m_Map.m_Frames.push_back(f.release());
         OFVector<FGBase*>::const_iterator fg = perFrameInformation.begin();
         while ( result.good() && (fg != perFrameInformation.end()) )
@@ -624,7 +616,11 @@ PixelType* DPMParametricMapIOD::Frames<PixelType>::getFrame(const size_t frameNu
 {
   if (frameNumber < m_Map.m_Frames.size())
   {
-    return (PixelType*)(m_Map.m_Frames[frameNumber]->pixData);
+    DcmIODTypes::Frame<PixelType> * f = OFstatic_cast(DcmIODTypes::Frame<PixelType>*, m_Map.m_Frames[frameNumber]);
+    if (f)
+    {
+      return f->m_pixData;
+    }
   }
   return NULL;
 }
@@ -913,6 +909,34 @@ OFBool DPMParametricMapIOD::check()
 }
 
 
+OFBool DPMParametricMapIOD::getCheckFGOnWrite()
+{
+  return m_FGInterface.getCheckOnWrite();
+}
+
+
+void DPMParametricMapIOD::setCheckFGOnWrite(const OFBool doCheck)
+{
+  m_FGInterface.setCheckOnWrite(doCheck);
+}
+
+
+void DPMParametricMapIOD::setValueCheckOnWrite(const OFBool doCheck)
+{
+  // Forward setting into all modules
+  m_DPMParametricMapSeriesModule.setValueCheckOnWrite(doCheck);
+  m_IODEnhGeneralEquipmentModule.setValueCheckOnWrite(doCheck);
+  m_IODMultiframeDimensionModule.setValueCheckOnWrite(doCheck);
+  m_IODAcquisitionContextModule.setValueCheckOnWrite(doCheck);
+  m_IODCommonInstanceReferenceModule.setValueCheckOnWrite(doCheck);
+
+  m_IODMultiFrameFGModule.setValueCheckOnWrite(doCheck);
+  m_DPMParametricMapImageModule.setValueCheckOnWrite(doCheck);
+  m_DPMParametricMapSeriesModule.setValueCheckOnWrite(doCheck);
+  DcmIODImage::setValueCheckOnWrite(doCheck);
+}
+
+
 OFCondition DPMParametricMapIOD::getColumns(Uint16& cols)
 {
   return getImagePixel().getColumns(cols);
index 0209208aa5a6b489dc8aa0d409045e6b6f99a033..fa173c34eabdf1c5f292258e60a435a9fd186cef 100644 (file)
@@ -8,9 +8,9 @@ endforeach()
 
 # make sure executables are linked to the corresponding libraries
 foreach(PROGRAM dcmp2pgm dcmprscp dcmprscu dcmpsmk dcmpschk dcmpsprt dcmpsrcv dcmpssnd)
-  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmpstat dcmdsig dcmsr dcmimage dcmimgle dcmqrdb dcmnet dcmtls dcmdata oflog ofstd)
+  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmpstat dcmdsig dcmsr dcmimage dcmimgle dcmqrdb dcmtls)
 endforeach()
 
 foreach(PROGRAM dcmmkcrv dcmmklut)
-  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmdsig dcmsr dcmimage dcmimgle dcmdata oflog ofstd)
+  DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmdsig dcmsr dcmimage dcmimgle)
 endforeach()
index 7364504cbd375b156404902453177679d5494d7e..292224c732fde06cc8f9c2ef86609931fb34a928 100644 (file)
@@ -916,7 +916,8 @@ dcmpschk.o: dcmpschk.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmpstat/dvpsall.h ../include/dcmtk/dcmpstat/dvpsgal.h \
  ../include/dcmtk/dcmpstat/dvpscul.h ../include/dcmtk/dcmpstat/dvpsvll.h \
  ../include/dcmtk/dcmpstat/dvpsvwl.h ../include/dcmtk/dcmpstat/dvpsdal.h \
- ../include/dcmtk/dcmpstat/dvpssvl.h ../include/dcmtk/dcmpstat/dvpspl.h
+ ../include/dcmtk/dcmpstat/dvpssvl.h ../include/dcmtk/dcmpstat/dvpspl.h \
+ ../include/dcmtk/dcmpstat/dvpsri.h
 dcmpsmk.o: dcmpsmk.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
@@ -1056,7 +1057,7 @@ dcmpsmk.o: dcmpsmk.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmpstat/dvpscul.h ../include/dcmtk/dcmpstat/dvpsvll.h \
  ../include/dcmtk/dcmpstat/dvpsvwl.h ../include/dcmtk/dcmpstat/dvpsdal.h \
  ../include/dcmtk/dcmpstat/dvpssvl.h ../include/dcmtk/dcmpstat/dvpspl.h \
- ../include/dcmtk/dcmpstat/dvpshlp.h
+ ../include/dcmtk/dcmpstat/dvpshlp.h ../include/dcmtk/dcmpstat/dvpsri.h
 dcmpsprt.o: dcmpsprt.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
@@ -1385,7 +1386,7 @@ dcmpsrcv.o: dcmpsrcv.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmpstat/dvpsgal.h ../include/dcmtk/dcmpstat/dvpscul.h \
  ../include/dcmtk/dcmpstat/dvpsvll.h ../include/dcmtk/dcmpstat/dvpsvwl.h \
  ../include/dcmtk/dcmpstat/dvpsdal.h ../include/dcmtk/dcmpstat/dvpssvl.h \
- ../include/dcmtk/dcmpstat/dvpspl.h \
+ ../include/dcmtk/dcmpstat/dvpspl.h ../include/dcmtk/dcmpstat/dvpsri.h \
  ../../dcmtls/include/dcmtk/dcmtls/tlstrans.h \
  ../../dcmnet/include/dcmtk/dcmnet/dcmtrans.h \
  ../../dcmtls/include/dcmtk/dcmtls/tlsdefin.h \
index 77f4ca5a1e664a9c31cf5b4b56a972e23e4f7583..052afbd5b89dd3cf974ca2da58bdbc9b424202cb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -22,9 +22,7 @@
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* for O_RDONLY */
-#endif
 END_EXTERN_C
 
 #include "dcmtk/ofstd/ofstream.h"
@@ -253,6 +251,8 @@ int main(int argc, char *argv[])
     unsigned short targetPort   = dvi.getTargetPort(opt_printer);
     OFBool targetDisableNewVRs  = dvi.getTargetDisableNewVRs(opt_printer);
     OFBool targetUseTLS         = dvi.getTargetUseTLS(opt_printer);
+    T_ASC_ProtocolFamily targetProtocol = dvi.getTargetProtocol(opt_printer);
+    dcmIncomingProtocolFamily.set(targetProtocol);
 
     if (targetPort == 0)
     {
index 94659cf129a37567cca2e93c236b54302eb9667d..dacdc55d24ca4b50716b624552845181ca277d78 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 1999-2024, OFFIS e.V.
+ *  Copyright (C) 1999-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -37,9 +37,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>      /* for O_RDONLY */
-#endif
 END_EXTERN_C
 
 #include "dcmtk/ofstd/ofstream.h"
index 697c2f4edfddef7af996d3dd5ed5edafd03bae97..4f0be022c5c8f957fb16221419c6195efd0e4ef8 100644 (file)
@@ -28,6 +28,7 @@
 #include "dcmtk/dcmdata/dctk.h"        /* for class DcmDataset */
 #include "dcmtk/dcmnet/dul.h"
 #include "dcmtk/dcmpstat/dcmpstat.h"   /* for DcmPresentationState */
+#include "dcmtk/dcmpstat/dvpsri.h"     /* for dcmPresentationStateValidationMode */
 #include "dcmtk/ofstd/ofstd.h"
 
 #ifdef WITH_ZLIB
@@ -911,7 +912,7 @@ static int checkfile(const char *filename)
 }
 
 #define SHORTCOL 3
-#define LONGCOL 12
+#define LONGCOL 18
 
 int main(int argc, char *argv[])
 {
@@ -936,6 +937,11 @@ int main(int argc, char *argv[])
      cmd.addOption("--version",            "print version information and exit", OFCommandLine::AF_Exclusive);
      OFLog::addOptions(cmd);
 
+    cmd.addGroup("validation options:");
+     cmd.addOption("--validate-std",       "images referenced by GSPS must belong to the\nsame SOP class (default)");
+     cmd.addOption("--validate-related",   "images referenced by GSPS may belong to related\n'for presentation' and 'for processing' SOP class");
+     cmd.addOption("--validate-relaxed",   "images referenced by GSPS may be any SOP class");
+
     /* evaluate command line */
     prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
     if (app.parseCommandLine(cmd, argc, argv))
@@ -956,6 +962,13 @@ int main(int argc, char *argv[])
          }
       }
 
+      /* validation options */
+      cmd.beginOptionBlock();
+      if (cmd.findOption("--validate-std")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_standard);
+      if (cmd.findOption("--validate-related")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_Presentation_and_Processing);
+      if (cmd.findOption("--validate-relaxed")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_all);
+      cmd.endOptionBlock();
+
       /* options */
       OFLog::configureFromCommandLine(cmd, app);
     }
@@ -963,6 +976,7 @@ int main(int argc, char *argv[])
     /* print resource identifier */
     OFLOG_DEBUG(dcmpschkLogger, rcsid << OFendl);
 
+
     int paramCount = cmd.getParamCount();
     for (int param=1; param <= paramCount; param++)
     {
index 57a914a79f92214e276c4dd2696546e277c13261..d40491f2b634c08e74fbb53d9e5b3d1b3fbca2da 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2022, OFFIS e.V.
+ *  Copyright (C) 1998-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -31,6 +31,7 @@
 #include "dcmtk/dcmnet/dul.h"
 #include "dcmtk/dcmpstat/dcmpstat.h"
 #include "dcmtk/dcmpstat/dvpshlp.h"
+#include "dcmtk/dcmpstat/dvpsri.h"     /* for dcmPresentationStateValidationMode */
 
 #ifdef WITH_ZLIB
 #include <zlib.h>        /* for zlibVersion() */
@@ -138,6 +139,11 @@ int main(int argc, char *argv[])
        cmd.addOption("--location-media",      "-lm", 2, "[f]ilesetID, fileset[UID]: string",
                                                         "image located on storage medium");
 
+    cmd.addGroup("validation options:", LONGCOL, SHORTCOL + 2);
+     cmd.addOption("--validate-std",                    "images referenced by GSPS must belong to the\nsame SOP class (default)");
+     cmd.addOption("--validate-related",                "images referenced by GSPS may belong to related\n'for presentation' and 'for processing'\nSOP class");
+     cmd.addOption("--validate-relaxed",                "images referenced by GSPS may be any SOP class");
+
     cmd.addGroup("output options:");
       cmd.addSubGroup("output transfer syntax:");
        cmd.addOption("--write-xfer-same",     "+t=",    "write with same TS as image file (default)");
@@ -242,6 +248,13 @@ int main(int argc, char *argv[])
       }
       cmd.endOptionBlock();
 
+      /* validation options */
+      cmd.beginOptionBlock();
+      if (cmd.findOption("--validate-std")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_standard);
+      if (cmd.findOption("--validate-related")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_Presentation_and_Processing);
+      if (cmd.findOption("--validate-relaxed")) dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_all);
+      cmd.endOptionBlock();
+
       cmd.beginOptionBlock();
       if (cmd.findOption("--write-xfer-same")) opt_oxfer = EXS_Unknown;
       if (cmd.findOption("--write-xfer-little")) opt_oxfer = EXS_LittleEndianExplicit;
index 4e7654794b28dd9cd3e074e2ee5c689602f79ac2..1a2bca777ea9cf0c4ee319260e5d8804c95a4808 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2024, OFFIS e.V.
+ *  Copyright (C) 1999-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* for O_RDONLY */
-#endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* required for sys/stat.h */
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat, fstat */
-#endif
 END_EXTERN_C
 
 #include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants */
@@ -47,6 +41,7 @@ END_EXTERN_C
 #include "dcmtk/dcmnet/dcmlayer.h"
 #include "dcmtk/dcmdata/dcfilefo.h"
 #include "dcmtk/dcmpstat/dcmpstat.h"
+#include "dcmtk/dcmpstat/dvpsri.h"     /* for dcmPresentationStateValidationMode */
 
 #ifdef WITH_OPENSSL
 #include "dcmtk/dcmtls/tlstrans.h"
@@ -854,11 +849,26 @@ int main(int argc, char *argv[])
     unsigned short networkPort    = dvi.getTargetPort(opt_cfgID);
     unsigned long  networkMaxPDU  = dvi.getTargetMaxPDU(opt_cfgID);
     const char *networkAETitle    = dvi.getTargetAETitle(opt_cfgID);
+    const char *validationMode    = dvi.getTargetValidationMode(opt_cfgID);
     if (networkAETitle==NULL) networkAETitle = dvi.getNetworkAETitle();
     unsigned short messagePort    = dvi.getMessagePort();   /* port number for IPC */
     OFBool keepMessagePortOpen    = dvi.getMessagePortKeepOpen();
     OFBool useTLS = dvi.getTargetUseTLS(opt_cfgID);
     OFBool notifyTermination      = OFTrue;  // notify IPC server of application termination
+    T_ASC_ProtocolFamily targetProtocol = dvi.getTargetProtocol(opt_cfgID);
+    dcmIncomingProtocolFamily.set(targetProtocol);
+
+    if (validationMode)
+    {
+      OFString vmode(validationMode);
+      if (vmode == "STD") dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_standard);
+      else if (vmode == "RELATED") dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_Presentation_and_Processing);
+      else if (vmode == "RELAXED") dcmPresentationStateValidationMode.set(DVPSReferencedImage::CVM_accept_all);
+      else
+      {
+        OFLOG_WARN(dcmpsrcvLogger, "unknown validation mode '" << vmode << "', ignoring");
+      }
+    }
 
 #ifdef WITH_OPENSSL
     /* TLS directory */
index 6877b1d36ae98c0c958eac9decc7c43596458c3d..d51861673f446ea3a17170a343643550ea8bbff8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2024, OFFIS e.V.
+ *  Copyright (C) 1999-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* for O_RDONLY */
-#endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* required for sys/stat.h */
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat, fstat */
-#endif
 END_EXTERN_C
 
 #include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants */
@@ -90,9 +84,9 @@ static OFCondition sendImage(T_ASC_Association *assoc, const char *sopClass, con
 #ifdef LOCK_IMAGE_FILES
     /* shared lock image file */
 #ifdef O_BINARY
-    int lockfd = open(imgFile, O_RDONLY | O_BINARY, 0666);
+    int lockfd = open(imgFile, O_RDONLY | O_BINARY);
 #else
-    int lockfd = open(imgFile, O_RDONLY, 0666);
+    int lockfd = open(imgFile, O_RDONLY);
 #endif
     if (lockfd < 0)
     {
index ea26aa013324e8bcd40e393dfae8cef5ebd9eb97..cc769f17b8664c99d9fca14be0988d3388926c10 100644 (file)
@@ -178,6 +178,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmmkcrv_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 59dd270efd9f3e3536e6bab1a1c0f417dce9359a..60bd8701c2dab1380657938d5faa621e9b85ea54 100644 (file)
@@ -248,6 +248,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmmklut_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index bb80a7277c26435b0eabb7f1394996cbb17d83a7..80a89b64a72b4c12b9866ad8ee3934c07d89864a 100644 (file)
@@ -170,6 +170,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmp2pgm_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 15f6611773c2c351a7a9c55c0d69ad8d3d291c01..c87d4f5bd6694ee02c7df27b8993cf3fcafad8c6 100644 (file)
@@ -133,7 +133,8 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmprscp_files FILES
 
-<em>\<etcdir\>/dcmpstat.cfg</em>, <em>\<etcdir\>/printers.cfg</em> - sample configuration files
+<em>\<etcdir\>/dcmpstat.cfg</em>, <em>\<etcdir\>/printers.cfg</em> - sample
+configuration files
 
 \section dcmprscp_see_also SEE ALSO
 
@@ -141,6 +142,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmprscp_copyright COPYRIGHT
 
-Copyright (C) 1999-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1999-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 5d1575e147919f221142bebf542a8ac05d43199c..ae7e2f0b727702a3be76de5b769b2221ccade34a 100644 (file)
@@ -193,7 +193,8 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmprscu_files FILES
 
-<em>\<etcdir\>/dcmpstat.cfg</em>, <em>\<etcdir\>/printers.cfg</em> - sample configuration files
+<em>\<etcdir\>/dcmpstat.cfg</em>, <em>\<etcdir\>/printers.cfg</em> - sample
+configuration files
 
 \section dcmprscu_see_also SEE ALSO
 
@@ -201,6 +202,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmprscu_copyright COPYRIGHT
 
-Copyright (C) 1999-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1999-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 0c813c0709bea6fe0cffa503e11c7c091cbf2263..76112dba41e0c5539b472af4d0220b629ed1e39c 100644 (file)
@@ -72,6 +72,20 @@ dcmfile-in  presentation state file(s) to be checked
          use config file f for the logger
 \endverbatim
 
+\subsection dcmpschk_validation_options validation options
+\verbatim
+       --validate-std
+         images referenced by GSPS must belong to the
+         same SOP class (default)
+
+       --validate-related
+         images referenced by GSPS may belong to related
+         'for presentation' and 'for processing' SOP class
+
+       --validate-relaxed
+         images referenced by GSPS may be any SOP class
+\endverbatim
+
 \section dcmpschk_logging LOGGING
 
 The level of logging output of the various command line tools and underlying
@@ -131,6 +145,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmpschk_copyright COPYRIGHT
 
-Copyright (C) 2000-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2000-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 17e300bf70ca2e8f7ce5349398f73305b0edfb0b..82f1410cb94e46bd11cb64b02aa6fe1c66114956 100644 (file)
@@ -163,6 +163,20 @@ location of referenced image:
          image located on storage medium
 \endverbatim
 
+\subsection dcmpsmk_validation_options validation options
+\verbatim
+       --validate-std
+          images referenced by GSPS must belong to the
+          same SOP class (default)
+
+       --validate-related
+          images referenced by GSPS may belong to related
+          'for presentation' and 'for processing' SOP class
+
+       --validate-relaxed
+          images referenced by GSPS may be any SOP class
+\endverbatim
+
 \subsection dcmpsmk_output_options output options
 \verbatim
 output transfer syntax:
@@ -245,6 +259,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmpsmk_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 50ddf9fc5c518741baa6973e637df2ed3fa3868c..321a5700fdc692dbce45d6d2af678511bddda2d0 100644 (file)
@@ -313,6 +313,6 @@ configuration files
 
 \section dcmpsprt_copyright COPYRIGHT
 
-Copyright (C) 1999-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1999-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 21a9552bcaedd4b6a8162dab798c19d0c99cf0a2..80fc570c2de2edcd11432fc25b376d242420a3b2 100644 (file)
@@ -130,6 +130,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmpsrcv_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 7f48ba44ced7d574b11558c59266f7441fa3316e..1f922edb65ee3cbd987e46e2e14d825005eea6cf 100644 (file)
@@ -138,6 +138,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmpssnd_copyright COPYRIGHT
 
-Copyright (C) 1998-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1998-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index a64f30f3cf96a97f1e369f7f3a8679aebb180ebf..a1864f93fe7a967b70f0bef72ad4b6373bf1ab6c 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 1998-2024, OFFIS e.V.
+#  Copyright (C) 1998-2025, OFFIS e.V.
 #  All rights reserved.  See COPYRIGHT file for details.
 #
 #  This software and supporting documentation were developed by
@@ -270,6 +270,12 @@ MaxAssociations = 16
 # than zero. Optional setting, default is Unlimited (wait for TCP/IP timeout).
 # Timeout = 5
 
+# IP protocol family to be used. Permitted values are AF_INET (IPv4 only),
+# AF_INET6 (IPv6 only) and AF_UNSPEC (for outgoing connections, use DNS
+# lookup to determine protocol, for incoming connections use dual-stack mode).
+# Optional setting, default is AF_INET.
+Protocol = AF_INET
+
 # ----------------------------------------------------------------------------
 # This section contains the settings for the graphical user interface (GUI).
 [GUI]
@@ -397,7 +403,8 @@ WarnUnsignedObjectsInSR = true
 # ----------------------------------------------------------------------------
 #
 # IP protocol family to be used. Permitted values are AF_INET (IPv4 only),
-# AF_INET6 (IPv6 only) and AF_UNSPEC (use DNS lookup to determine protocol).
+# AF_INET6 (IPv6 only) and AF_UNSPEC (for outgoing connections, use DNS
+# lookup to determine protocol, for incoming connections use dual-stack mode).
 # Optional setting, default is AF_INET.
 #
 # protocol = AF_INET
@@ -572,6 +579,23 @@ WarnUnsignedObjectsInSR = true
 #
 # RandomSeed = random.dat
 #
+# ============================================================================
+# The next settings described below is only used with entries of type
+# RECEIVER and have no meaning for other entry types.
+# ============================================================================
+#
+# Set validation mode for incoming presentation states.
+# Default is to enforce the rule that all images referenced by one presentation
+# state must belong to the same SOP class. This can be relaxed to accept either
+# related 'for presentation' and 'for processing' SOP class references in
+# one presentation state, or to not enforce this rule at all.
+# Known terms are:
+#   STD: enforce the one SOP class rule as defined in the standard
+#   RELATED: permit related 'for presentation'/'for processing' SOP classes
+#   RELAXED: images referenced by GSPS may be of any SOP class
+# Optional setting, default is: STD.
+#
+# ValidationMode = STD
 #
 # ============================================================================
 # The next two settings described below are only used with entries of type
@@ -999,6 +1023,7 @@ Port = 10004
 ImplicitOnly  = false
 DisableNewVRs = false
 BitPreservingMode = false
+ValidationMode = STD
 
 # ----------------------------------------------------------------------------
 [RECEIVE_2]
@@ -1020,6 +1045,7 @@ RandomSeed = receiver.rnd
 PeerAuthentication = REQUIRE
 Certificate = sitecert.pem
 PrivateKey = sitekey.pem
+ValidationMode = STD
 
 # ----------------------------------------------------------------------------
 # Print SCP that supports most options of the DICOM Print protocol and
index 11a550399c30b5ce685503b31eec287d57e4bb56..d27ef422928bbee93816f9fe4f245e430925c799 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2022, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
index 155769f053f28a2455500b479f7df4bee919481c..45da1bce6094526d2a262c38c870a0341342b741 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -160,6 +160,14 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    */
   OFBool getTargetBitPreservingMode(const char *targetID);
 
+  /** returns the VALIDATIONMODE entry for the storage peer with the given
+   *  target ID from the configuration file.
+   *  @param targetID communication target ID, must be one of the target
+   *    identifiers returned by getTargetID().
+   *  @return entry if present in the config file, NULL otherwise.
+   */
+  const char *getTargetValidationMode(const char *targetID);
+
   /** returns the CORRECTUIDPADDING entry for the storage peer with the given
    *  target ID from the configuration file.
    *  @param targetID communication target ID, must be one of the target
@@ -398,7 +406,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    */
   OFBool getTargetPrinterSupportsAnnotationBoxSOPClass(const char *targetID);
 
-  /** returns OFTrue if an SESSIONLABELANNOTATION entry for the printer 
+  /** returns OFTrue if an SESSIONLABELANNOTATION entry for the printer
    *  with the given target ID from the configuration file exists and is true.
    *  @param targetID communication target ID, must be one of the target
    *    identifiers returned by getTargetID() for peer type DVPSE_printerAny.
@@ -414,7 +422,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    *  @return value if present, NULL otherwise.
    */
   const char *getTargetPrinterAnnotationDisplayFormatID(const char *targetID, OFString& value);
-  
+
   /** returns the first value from the ANNOTATION entry for the printer
    *  with the given target ID from the configuration file.
    *  @param targetID communication target ID, must be one of the target
@@ -422,7 +430,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    *  @return value if present, 0 otherwise.
    */
   Uint16 getTargetPrinterAnnotationPosition(const char *targetID);
-  
+
   /** returns the number of distinct values (separated by backslash characters)
    *  in the FILMSIZEID entry for the printer with the given
    *  target ID from the configuration file.
@@ -604,7 +612,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    */
   OFLogger::LogLevel getLogLevel();
 
-  /** returns the port on which the GUI application accepts notification 
+  /** returns the port on which the GUI application accepts notification
    *  messages from the network processes.
    *  Value is taken from the section GENERAL/APPLICATION/MESSAGEPORT
    *  in the config file.
@@ -664,6 +672,12 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    */
   unsigned long getQueryRetrieveMaxAssociations();
 
+  /** returns the protocol family to be supported by the Query/Retrieve SCP
+   *  as configured in section GENERAL/QUERY_RETRIEVE/PROTOCOL in the config file.
+   *  @return send application path name or NULL if absent.
+   */
+  T_ASC_ProtocolFamily getQueryRetrieveProtocolFamily();
+
   /** returns the database folder to be used for sending/receiving/browsing.
    *  Value is taken from the section GENERAL/DATABASE/DIRECTORY
    *  in the config file. If absent, a default value is returned.
@@ -945,22 +959,22 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
   double getVOIPresetWindowWidth(const char *modality, Uint32 idx);
 
   /* TLS settings */
-  
-  /** returns the directory in which TLS related files (certificates, keys, 
-   *  random data, Diffie-Hellman parameters etc.) are located. 
+
+  /** returns the directory in which TLS related files (certificates, keys,
+   *  random data, Diffie-Hellman parameters etc.) are located.
    *  @return TLS directory path, NULL if absent.
    */
   const char *getTLSFolder();
 
-  /** returns the directory in which certificates of the trusted 
-   *  Certification Authorities are located. 
+  /** returns the directory in which certificates of the trusted
+   *  Certification Authorities are located.
    *  @return TLS CA Certificate directory path, NULL if absent.
    */
   const char *getTLSCACertificateFolder();
 
   /** returns the file format used for certificates, keys and Diffie-Hellman
    *  parameters. OFTrue for PEM ("privacy enhanced mail") format, OFFalse for
-   *  DER ("distinguished encoding rules") format.  
+   *  DER ("distinguished encoding rules") format.
    *  @return OFTrue for PEM (default), OFFalse for DER.
    */
   OFBool getTLSPEMFormat();
@@ -968,7 +982,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
   /* User login settings */
 
   /** returns the directory in which user certificates and keys
-   *  are located. 
+   *  are located.
    *  @return User key/certificate directory path, NULL if absent.
    */
   const char *getUserCertificateFolder();
@@ -992,7 +1006,7 @@ class DCMTK_DCMPSTAT_EXPORT DVConfiguration
    */
   const char *getUserLogin(const char *userID);
 
-  /** returns the human readable name for the given user. 
+  /** returns the human readable name for the given user.
    *  If absent in the config file, returns NULL.
    *  @param userID user ID as returned by getUserID()
    *  @return name for the given user
index 0faa4401cfb11b50c36e598e2aee6a178ee602b0..9e7abb248c9f1127e480c5712b842d378c6b04e5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2012, OFFIS e.V.
+ *  Copyright (C) 1998-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 class DCMTK_DCMPSTAT_EXPORT DVPSReferencedImage
 {
+public:
+    /** SOPClassUID Validation Mode
+     */
+    enum E_ClassValidationMode
+    {
+        /** enforce the rule specified in DICOM Part 3, C.11.11,
+         *  that the referenced SOP class must be same for all images
+         *  referenced by a presentation state.
+         */
+        CVM_standard,
+
+        /** somewhat relax the rule that the referenced SOP class must
+         *  be same for all images referenced by a presentation state
+         *  by permitting instances of related "for presentation" and
+         *  "for processing" SOP classes to be referenced from one
+         *  presentation state.
+         */
+
+        CVM_accept_Presentation_and_Processing,
+
+        /** ignore the rule that the referenced SOP class must
+         *  be same for all images referenced by a presentation state
+         */
+        CVM_accept_all
+    };
+
 public:
   /// default constructor
   DVPSReferencedImage();
@@ -170,4 +196,10 @@ private:
 
 };
 
+/** This flag defines the validation mode applied when reading presentation
+ *  states. See definition of enum E_ClassValidationMode for details.
+ *  The default is CVM_standard.
+ */
+extern DCMTK_DCMPSTAT_EXPORT OFGlobal<DVPSReferencedImage::E_ClassValidationMode> dcmPresentationStateValidationMode;
+
 #endif
index 1602dfb2b9bdd20b2e0dd2a36fa90f38c10977a4..f844e0a979bc518f83b749fea3e6c2d5fa24cb39 100644 (file)
@@ -2966,6 +2966,7 @@ dvpspl2.o: dvpspl2.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didispfn.h \
@@ -3070,6 +3071,7 @@ dvpspll.o: dvpspll.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
  ../include/dcmtk/dcmpstat/dvpsibl.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diutils.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didefine.h \
@@ -3110,7 +3112,6 @@ dvpspll.o: dvpspll.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvruc.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixel.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpobw.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcovlay.h \
@@ -3432,7 +3433,8 @@ dvpsri.o: dvpsri.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
- ../include/dcmtk/dcmpstat/dvpsdef.h
+ ../include/dcmtk/dcmpstat/dvpsdef.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
 dvpsril.o: dvpsril.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmpstat/dvpsril.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
index 3b7cdc07e70470a7394badf65fa58f42c9d9403b..0a550352f0188837b484cf35d980a9c22c85ab7f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -64,9 +64,7 @@
 #include "dcmtk/dcmqrdb/dcmqrdbs.h"   /* for DcmQueryRetrieveDatabaseStatus */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* for fork */
-#endif
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>    /* for waitpid */
 #endif
@@ -76,9 +74,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h> /* for wait3 */
 #endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat, fstat */
-#endif
 #ifdef HAVE_SYS_UTIME_H
 #include <sys/utime.h>   /* for utime */
 #endif
@@ -2375,6 +2371,7 @@ OFCondition DVInterface::startQueryRetrieveServer()
   if (configPath.empty()) return EC_IllegalCall;
 
   OFString config_filename = getQueryRetrieveServerName();
+  T_ASC_ProtocolFamily family = getQueryRetrieveProtocolFamily();
   config_filename += ".cfg";
   if (getQueryRetrieveAutoCreateConfigFile())
     createQueryRetrieveServerConfigFile(config_filename.c_str());
@@ -2384,6 +2381,20 @@ OFCondition DVInterface::startQueryRetrieveServer()
   DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
 
   Sint32 timeout = getQueryRetrieveTimeout();
+  const char *family_param = "";
+  switch (family)
+  {
+    case ASC_AF_INET:
+    case ASC_AF_Default:
+      family_param = "--ipv4";
+      break;
+    case ASC_AF_INET6:
+      family_param = "--ipv6";
+      break;
+    case ASC_AF_UNSPEC:
+      family_param = "--ip-auto";
+      break;
+  }
 
 #ifdef HAVE_FORK
   // Unix version - call fork() and execl()
@@ -2402,12 +2413,11 @@ OFCondition DVInterface::startQueryRetrieveServer()
     {
       char str_timeout[20];
       OFStandard::snprintf(str_timeout, sizeof(str_timeout), "%lu", OFstatic_cast(unsigned long, timeout));
-      execl(server_application, server_application, "-c", config_filename.c_str(), "--allow-shutdown",
-        "--timeout", str_timeout, OFreinterpret_cast(char *, 0));
+      execl(server_application, server_application, "-c", config_filename.c_str(), family_param, "--allow-shutdown", "--timeout", str_timeout, OFreinterpret_cast(char *, 0));
     }
     else
     {
-      execl(server_application, server_application, "-c", config_filename.c_str(), "--allow-shutdown", OFreinterpret_cast(char *, 0));
+      execl(server_application, server_application, "-c", config_filename.c_str(), family_param, "--allow-shutdown", OFreinterpret_cast(char *, 0));
     }
 
     DCMPSTAT_ERROR("Unable to execute '" << server_application << "'");
@@ -2427,12 +2437,12 @@ OFCondition DVInterface::startQueryRetrieveServer()
 
   if (timeout > 0)
   {
-    OFStandard::snprintf(commandline, sizeof(commandline), "%s -c %s --allow-shutdown --timeout %lu",
-      server_application, config_filename.c_str(), (unsigned long) timeout);
+    OFStandard::snprintf(commandline, sizeof(commandline), "%s -c %s %s --allow-shutdown --timeout %lu",
+      server_application, config_filename.c_str(), family_param, (unsigned long) timeout);
   }
   else
   {
-    OFStandard::snprintf(commandline, sizeof(commandline), "%s -c %s --allow-shutdown", server_application, config_filename.c_str());
+    OFStandard::snprintf(commandline, sizeof(commandline), "%s -c %s %s --allow-shutdown", server_application, config_filename.c_str(), family_param);
   }
 
 #ifdef DEBUG
index 7f8cd14262fdd16d48ae20152a7d5a3f9c3c343c..9dc74dc0154d7bdb6cb1ff8e3a39f0182b95f497 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -71,7 +71,7 @@ extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
 #define L0_DESCRIPTION                  "DESCRIPTION"
 #define L0_DETAILEDLOG                  "DETAILEDLOG"
 #define L0_DICOMNAME                    "DICOMNAME"
-#define L0_DIFFIEHELLMANPARAMETERS      "DIFFIEHELLMANPARAMETERS"   
+#define L0_DIFFIEHELLMANPARAMETERS      "DIFFIEHELLMANPARAMETERS"
 #define L0_DIRECTORY                    "DIRECTORY"
 #define L0_DISABLENEWVRS                "DISABLENEWVRS"
 #define L0_DISPLAYFORMAT                "DISPLAYFORMAT"
@@ -134,6 +134,7 @@ extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
 #define L0_USEPEMFORMAT                 "USEPEMFORMAT"
 #define L0_USERKEYDIRECTORY             "USERKEYDIRECTORY"
 #define L0_USETLS                       "USETLS"
+#define L0_VALIDATIONMODE               "VALIDATIONMODE"
 #define L0_WIDTH                        "WIDTH"
 #define L1_APPLICATION                  "APPLICATION"
 #define L1_DATABASE                     "DATABASE"
@@ -224,7 +225,7 @@ static int strCompare(const char *str1, const char *str2, size_t len)
   return _strnicmp(str1, str2, len);
 #else
   return strncasecmp(str1, str2, len);
-#endif    
+#endif
 }
 
 
@@ -562,6 +563,19 @@ unsigned long DVConfiguration::getQueryRetrieveMaxAssociations()
   return result;
 }
 
+T_ASC_ProtocolFamily DVConfiguration::getQueryRetrieveProtocolFamily()
+{
+  const char *c = getConfigEntry(L2_GENERAL, L1_QUERY_RETRIEVE, L0_PROTOCOL);
+  T_ASC_ProtocolFamily result = ASC_AF_Default;
+  if (c)
+  {
+    if (strCompare(c, "AF_INET6", 8) == 0) result = ASC_AF_INET6;
+    else if (strCompare(c, "AF_INET", 7) == 0) result = ASC_AF_INET;
+    else if (strCompare(c, "AF_UNSPEC", 9) == 0) result = ASC_AF_UNSPEC;
+  }
+  return result;
+}
+
 const char *DVConfiguration::getDatabaseFolder()
 {
   const char *result = getConfigEntry(L2_GENERAL, L1_DATABASE, L0_DIRECTORY);
@@ -1303,7 +1317,7 @@ const char *DVConfiguration::getTargetPrinterAnnotationDisplayFormatID(const cha
   copyValue(getConfigEntry(L2_COMMUNICATION, targetID, L0_ANNOTATION), 1, value);
   if (value.length()) return value.c_str(); else return NULL;
 }
-    
+
 Uint16 DVConfiguration::getTargetPrinterAnnotationPosition(const char *targetID)
 {
   OFString value;
@@ -1331,6 +1345,11 @@ OFBool DVConfiguration::getTLSPEMFormat()
   return getConfigBoolEntry(L2_GENERAL, L1_TLS, L0_USEPEMFORMAT, OFTrue);
 }
 
+const char *DVConfiguration::getTargetValidationMode(const char *targetID)
+{
+  return getConfigEntry(L2_COMMUNICATION, targetID, L0_VALIDATIONMODE);
+}
+
 OFBool DVConfiguration::getTargetBitPreservingMode(const char *targetID)
 {
   return getConfigBoolEntry(L2_COMMUNICATION, targetID, L0_BITPRESERVINGMODE, OFFalse);
index fd1057a137eec58e9c7510f58629eb5a93b0917a..097a4a90891a182b14c1bf2b1d04f47632eabcce 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -27,9 +27,7 @@
 #include "dcmtk/dcmdata/dctk.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* for fork */
-#endif
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>    /* for waitpid */
 #endif
index 743c023b08a2ce2985051696636f94a4c81d7c2e..ac0da5ad043420a0fa00fc5168272baeb34ddf46 100644 (file)
@@ -279,6 +279,10 @@ void DVPSIPCClient::requestConnection()
 {
   if (connection) return; // connection already open
 
+  OFSockAddr server;
+  OFStandard::getAddressByHostname("localhost", AF_INET, server);
+  if (server.size() == 0) return;
+
 #ifdef _WIN32
   SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
   if (s == INVALID_SOCKET) return;
@@ -286,8 +290,7 @@ void DVPSIPCClient::requestConnection()
   int s = socket(AF_INET, SOCK_STREAM, 0);
   if (s < 0) return;
 #endif
-  OFSockAddr server;
-  OFStandard::getAddressByHostname("localhost", AF_INET, server);
+
   server.setPort(OFstatic_cast(unsigned short, htons(OFstatic_cast(unsigned short, port))));
 
   if (connect(s, server.getSockaddr(), server.size()) < 0)
index 2cc9d11ec49c9e774db49c42674b96b8e83fd3d5..9f742c2a200bae2780e9915cc21e0800a3ccba90 100644 (file)
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcitem.h"
 #include "dcmtk/dcmpstat/dvpsdef.h"   /* for constants and macros */
+#include "dcmtk/dcmdata/dcuid.h"
 #include "dcmtk/ofstd/ofstd.h"
 
+OFGlobal<DVPSReferencedImage::E_ClassValidationMode> dcmPresentationStateValidationMode(DVPSReferencedImage::CVM_standard);
+
 /* --------------- class DVPSReferencedImage --------------- */
 
+
 DVPSReferencedImage::DVPSReferencedImage()
 : referencedSOPClassUID(DCM_ReferencedSOPClassUID)
 , referencedSOPInstanceUID(DCM_ReferencedSOPInstanceUID)
@@ -58,11 +62,11 @@ OFCondition DVPSReferencedImage::read(DcmItem &dset)
   DcmStack stack;
 
   flushCache();
-  
+
   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, referencedSOPClassUID)
   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, referencedSOPInstanceUID)
   READ_FROM_DATASET(DcmIntegerString, EVR_IS, referencedFrameNumber)
-  
+
   /* Now perform basic sanity checks */
 
   if (referencedSOPClassUID.getLength() == 0)
@@ -94,7 +98,7 @@ OFCondition DVPSReferencedImage::write(DcmItem &dset)
 {
   OFCondition result = EC_Normal;
   DcmElement *delem=NULL;
-  
+
   ADD_TO_DATASET(DcmUniqueIdentifier, referencedSOPClassUID)
   ADD_TO_DATASET(DcmUniqueIdentifier, referencedSOPInstanceUID)
   if (referencedFrameNumber.getLength() >0) { ADD_TO_DATASET(DcmIntegerString, referencedFrameNumber) }
@@ -104,19 +108,64 @@ OFCondition DVPSReferencedImage::write(DcmItem &dset)
 
 OFBool DVPSReferencedImage::validateSOPClassUID(OFString& sopclassuid)
 {
-  OFBool result = OFTrue;
+  E_ClassValidationMode classValidationMode = dcmPresentationStateValidationMode.get();
   if (sopclassuid.empty()) referencedSOPClassUID.getOFString(sopclassuid, 0);
-  else 
+  else
   {
     OFString currentUID;
     referencedSOPClassUID.getOFString(currentUID, 0);
-    if (currentUID != sopclassuid)
+    switch (classValidationMode)
     {
-      result = OFFalse;
-      DCMPSTAT_WARN("images of different SOP classes referenced in presentation state");
+       // we accept all combinations of SOP classes
+       case CVM_accept_all:
+         if (currentUID != sopclassuid)
+         {
+             DCMPSTAT_INFO("images of different SOP classes referenced in presentation state");
+         }
+         return OFTrue;
+         /* break; */
+
+       // we accept only related SOP classes
+       case CVM_accept_Presentation_and_Processing:
+         if (currentUID != sopclassuid)
+         {
+            if (  ( sopclassuid == UID_BreastProjectionXRayImageStorageForPresentation && currentUID == UID_BreastProjectionXRayImageStorageForProcessing )
+               || ( sopclassuid == UID_BreastProjectionXRayImageStorageForProcessing && currentUID == UID_BreastProjectionXRayImageStorageForPresentation )
+               || ( sopclassuid == UID_DigitalIntraOralXRayImageStorageForPresentation && currentUID == UID_DigitalIntraOralXRayImageStorageForProcessing )
+               || ( sopclassuid == UID_DigitalIntraOralXRayImageStorageForProcessing && currentUID == UID_DigitalIntraOralXRayImageStorageForPresentation )
+               || ( sopclassuid == UID_DigitalMammographyXRayImageStorageForPresentation && currentUID == UID_DigitalMammographyXRayImageStorageForProcessing )
+               || ( sopclassuid == UID_DigitalMammographyXRayImageStorageForProcessing && currentUID == UID_DigitalMammographyXRayImageStorageForPresentation )
+               || ( sopclassuid == UID_DigitalXRayImageStorageForPresentation && currentUID == UID_DigitalXRayImageStorageForProcessing )
+               || ( sopclassuid == UID_DigitalXRayImageStorageForProcessing && currentUID == UID_DigitalXRayImageStorageForPresentation )
+               || ( sopclassuid == UID_IntravascularOpticalCoherenceTomographyImageStorageForPresentation && currentUID == UID_IntravascularOpticalCoherenceTomographyImageStorageForProcessing )
+               || ( sopclassuid == UID_IntravascularOpticalCoherenceTomographyImageStorageForProcessing && currentUID == UID_IntravascularOpticalCoherenceTomographyImageStorageForPresentation )
+               || ( sopclassuid == UID_DICOS_DigitalXRayImageStorageForPresentation && currentUID == UID_DICOS_DigitalXRayImageStorageForProcessing )
+               || ( sopclassuid == UID_DICOS_DigitalXRayImageStorageForProcessing && currentUID == UID_DICOS_DigitalXRayImageStorageForPresentation ) )
+            {
+                DCMPSTAT_INFO("images of different (but related) SOP classes referenced in presentation state");
+                return OFTrue;
+            }
+            else
+            {
+                DCMPSTAT_WARN("images of different SOP classes referenced in presentation state");
+                return OFFalse;
+            }
+         }
+         return OFTrue;
+         /* break; */
+
+       // we accept only the same SOP classes, as required by the DICOM standard
+       case CVM_standard:
+         if (currentUID != sopclassuid)
+         {
+             DCMPSTAT_WARN("images of different SOP classes referenced in presentation state");
+             return OFFalse;
+         }
+         else return OFTrue;
+         /* break; */
     }
   }
-  return result;
+  return OFTrue;
 }
 
 void DVPSReferencedImage::setSOPClassUID(const char *uid)
@@ -150,7 +199,7 @@ OFBool DVPSReferencedImage::isSOPInstanceUID(const char *uid)
 
 OFCondition DVPSReferencedImage::getImageReference(
     OFString& sopclassUID,
-    OFString& instanceUID, 
+    OFString& instanceUID,
     OFString& frames)
 {
   OFCondition result = referencedSOPClassUID.getOFString(sopclassUID,0);
@@ -204,7 +253,7 @@ OFBool DVPSReferencedImage::appliesToFrame(unsigned long frame)
   {
     val = (Sint32) frame;
     for (i=0; i<frameCacheEntries; i++) if (val == frameCache[i]) return OFTrue;
-    return OFFalse;    
+    return OFFalse;
   }
   return OFTrue; // referencedFrameNumber seems to contain garbage.
 }
@@ -227,14 +276,14 @@ void DVPSReferencedImage::removeFrameReference(unsigned long frame, unsigned lon
   unsigned long i;
   char str[20];
   OFString aString;
-  
+
   updateCache();
   referencedFrameNumber.clear();
   if (frameCache)
   {
-    for (i=0; i<frameCacheEntries; i++) 
+    for (i=0; i<frameCacheEntries; i++)
     {
-      if (frameCache[i] != (Sint32)frame) 
+      if (frameCache[i] != (Sint32)frame)
       {
        if (aString.size() ==0) OFStandard::snprintf(str, sizeof(str), "%ld", (long)(frameCache[i]));
           else OFStandard::snprintf(str, sizeof(str), "\\%ld", (long)(frameCache[i]));
@@ -242,7 +291,7 @@ void DVPSReferencedImage::removeFrameReference(unsigned long frame, unsigned lon
       }
     }
   } else {
-    for (i=1; i<=numberOfFrames; i++) 
+    for (i=1; i<=numberOfFrames; i++)
     {
       if (i != frame)
       {
index 3b30f5096b5ac8e5abf908200d053ff6616c0a3e..98e52e0e4abcae088021e9fdf243f0b146a64308 100644 (file)
@@ -2,4 +2,4 @@
 DCMTK_ADD_TEST_EXECUTABLE(msgserv msgserv.cc)
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(msgserv dcmpstat dcmdsig dcmsr dcmimage dcmimgle dcmqrdb dcmnet dcmtls dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(msgserv dcmpstat dcmdsig dcmsr dcmimage)
index dd5f45fd93125d6975fe0c70e98dd42b6161b76f..14379c83ee6bb19ac64deae360cde4700eba2f02 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024 OFFIS e.V.
+ *  Copyright (C) 2000-2025 OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -29,9 +29,7 @@
 #endif
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* we have to include this before sys/time.h on Solaris */
-#endif
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>    /* for struct timeval on Linux */
 #endif
index b4ddc2b304217709c086703ea530bf0fd00ac8e5..d546c0dbedaead0a8b9c5622a7aa8addb839a229 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2024, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -25,9 +25,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_FILE_H
 #include <sys/file.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
@@ -131,7 +129,6 @@ main(int argc, char *argv[])
 #endif
 
   OFCommandLine cmd;
-
   cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
   cmd.addParam("port", "tcp/ip port number to listen on\n(default: in config file)", OFCmdParam::PM_Optional);
 
@@ -185,6 +182,11 @@ main(int argc, char *argv[])
 #endif
 
   cmd.addGroup("network options:");
+    cmd.addSubGroup("IP protocol version:");
+      cmd.addOption("--ipv4",                   "-i4",     "use IPv4 only (default)");
+      cmd.addOption("--ipv6",                   "-i6",     "use IPv6 only");
+      cmd.addOption("--ip-auto",                "-i0",     "use IPv6/IPv4 dual stack");
+
     cmd.addSubGroup("association negotiation profiles from configuration file:");
       cmd.addOption("--assoc-config-file",      "-xf",  3, "[f]ilename, [i]n-prof, [o]ut-prof: string",
                                                            "use profile i from f for incoming,\nand profile o from f for outgoing associations");
@@ -518,6 +520,13 @@ main(int argc, char *argv[])
       if (cmd.findOption("--ignore")) options.ignoreStoreData_ = OFTrue;
       if (cmd.findOption("--uid-padding")) options.correctUIDPadding_ = OFTrue;
 
+      // set the IP protocol version
+      cmd.beginOptionBlock();
+      if (cmd.findOption("--ipv4")) dcmIncomingProtocolFamily.set(ASC_AF_INET);
+      if (cmd.findOption("--ipv6")) dcmIncomingProtocolFamily.set(ASC_AF_INET6);
+      if (cmd.findOption("--ip-auto")) dcmIncomingProtocolFamily.set(ASC_AF_UNSPEC);
+      cmd.endOptionBlock();
+
       if (cmd.findOption("--assoc-config-file"))
       {
         // check conflicts with other command line options
@@ -798,6 +807,7 @@ main(int argc, char *argv[])
 
       // evaluate (most of) the TLS command line options (if we are compiling with OpenSSL)
       tlsOptions.parseArguments(app, cmd);
+      options.secureConnectionRequested_ = tlsOptions.secureConnectionRequested();
     }
 
     /* print resource identifier */
index 7f4c6e0b893a0931255da2ac0706877f09743226..d74f0951b689929a380f0dafb958d0ab5a0b2539 100644 (file)
@@ -131,6 +131,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmqridx_copyright COPYRIGHT
 
-Copyright (C) 1993-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1993-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index cf820047c1c802050268cf4f5892ffddfd29e1f9..3c31b3a8d9ba798968775beda24a3b4287f388fb 100644 (file)
@@ -183,6 +183,17 @@ restriction of query/retrieve models:
 
 \subsection dcmqrscp_network_options network options
 \verbatim
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profiles from configuration file:
 
   -xf   --assoc-config-file
@@ -894,6 +905,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -1041,6 +1054,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -1114,7 +1128,7 @@ Query/Retrieve Level: PATIENT (or STUDY for the Study Root Q/R model)
 (0010,0040) PatientSex
 (0010,1000) OtherPatientIDs (retired)
 (0010,1001) OtherPatientNames
-(0010,2160) EthnicGroup
+(0010,2160) EthnicGroup (retired)
 (0010,4000) PatientComments
 \endverbatim
 
@@ -1135,7 +1149,7 @@ Query/Retrieve Level: STUDY
 (0010,21B0) AdditionalPatientHistory
 (0020,000D) StudyInstanceUID
 (0020,0010) StudyID
-(0020,1070) RETIRED_OtherStudyNumbers
+(0020,1070) OtherStudyNumbers (retired)
 \endverbatim
 
 Query/Retrieve Level: SERIES
@@ -1248,6 +1262,6 @@ profiles
 
 \section dcmqrscp_copyright COPYRIGHT
 
-Copyright (C) 1993-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1993-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 23fa203fe7c03c3fe868f02cd93c097e64d76f01..9618224515e035c380baccc5538a8e0e0eaf4251 100644 (file)
@@ -443,6 +443,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmqrti_copyright COPYRIGHT
 
-Copyright (C) 1993-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1993-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 8c5a72b2090fd49359eaef7ee3bbc37d48998331..2f3d96265245a9a45646209cd7626bd275fa7072 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2017-2024, OFFIS e.V.
+#  Copyright (C) 2017-2025, OFFIS e.V.
 #  All rights reserved.  See COPYRIGHT file for details.
 #
 #  This software and supporting documentation were developed by
@@ -44,6 +44,9 @@ TransferSyntax1  = DeflatedLittleEndianExplicit
 TransferSyntax2  = LocalEndianExplicit
 TransferSyntax3  = OppositeEndianExplicit
 TransferSyntax4  = LittleEndianImplicit
+#
+# The "Deflated Image Frame Compression" transfer syntax is for images.
+#
 
 [UncompressedEncapsulatedOrZlib]
 TransferSyntax1  = DeflatedLittleEndianExplicit
@@ -53,6 +56,8 @@ TransferSyntax4  = LittleEndianImplicit
 #
 # The retired "Big Endian Explicit" transfer syntax is not accepted.
 #
+# The "Deflated Image Frame Compression" transfer syntax is for images.
+#
 
 [JPEGBaseline]
 TransferSyntax1 = JPEGBaseline
@@ -136,11 +141,12 @@ TransferSyntax44 = HighThroughputJPEG2000ImageCompression
 TransferSyntax45 = JPEGXLLossless
 TransferSyntax46 = JPEGXLJPEGRecompression
 TransferSyntax47 = JPEGXL
-TransferSyntax48 = DeflatedLittleEndianExplicit
-TransferSyntax49 = EncapsulatedUncompressedLittleEndianExplicit
-TransferSyntax50 = LocalEndianExplicit
-TransferSyntax51 = OppositeEndianExplicit
-TransferSyntax52 = LittleEndianImplicit
+TransferSyntax48 = DeflatedImageFrameCompression
+TransferSyntax49 = DeflatedLittleEndianExplicit
+TransferSyntax50 = EncapsulatedUncompressedLittleEndianExplicit
+TransferSyntax51 = LocalEndianExplicit
+TransferSyntax52 = OppositeEndianExplicit
+TransferSyntax53 = LittleEndianImplicit
 
 # ============================================================================
 [[PresentationContexts]]
@@ -343,46 +349,49 @@ PresentationContext178 = TwelveLeadECGWaveformStorage\UncompressedOrZlib
 PresentationContext179 = VariableModalityLUTSoftcopyPresentationStateStorage\UncompressedOrZlib
 PresentationContext180 = VisualAcuityMeasurementsStorage\UncompressedOrZlib
 PresentationContext181 = VolumeRenderingVolumetricPresentationStateStorage\UncompressedOrZlib
-PresentationContext182 = WaveformAnnotationSRStorage\UncompressedOrZlib
-PresentationContext183 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext184 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
-PresentationContext185 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
-PresentationContext186 = XRayRadiationDoseSRStorage\UncompressedOrZlib
+PresentationContext182 = WaveformAcquisitionPresentationStateStorage\UncompressedOrZlib
+PresentationContext183 = WaveformAnnotationSRStorage\UncompressedOrZlib
+PresentationContext184 = WaveformPresentationStateStorage\UncompressedOrZlib
+PresentationContext185 = XADefinedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext186 = XAPerformedProcedureProtocolStorage\UncompressedOrZlib
+PresentationContext187 = XAXRFGrayscaleSoftcopyPresentationStateStorage\UncompressedOrZlib
+PresentationContext188 = XRayRadiationDoseSRStorage\UncompressedOrZlib
 #
 # retired non-image SOP classes
 #
-PresentationContext187 = RETIRED_StandaloneCurveStorage\UncompressedOrZlib
-PresentationContext188 = RETIRED_StandaloneModalityLUTStorage\UncompressedOrZlib
-PresentationContext189 = RETIRED_StandaloneOverlayStorage\UncompressedOrZlib
-PresentationContext190 = RETIRED_StandalonePETCurveStorage\UncompressedOrZlib
-PresentationContext191 = RETIRED_StandaloneVOILUTStorage\UncompressedOrZlib
-PresentationContext192 = RETIRED_StoredPrintStorage\UncompressedOrZlib
+PresentationContext189 = RETIRED_StandaloneCurveStorage\UncompressedOrZlib
+PresentationContext190 = RETIRED_StandaloneModalityLUTStorage\UncompressedOrZlib
+PresentationContext191 = RETIRED_StandaloneOverlayStorage\UncompressedOrZlib
+PresentationContext192 = RETIRED_StandalonePETCurveStorage\UncompressedOrZlib
+PresentationContext193 = RETIRED_StandaloneVOILUTStorage\UncompressedOrZlib
+PresentationContext194 = RETIRED_StoredPrintStorage\UncompressedOrZlib
 #
 # draft non-image SOP classes
 #
-PresentationContext193 = DRAFT_RTBeamsDeliveryInstructionStorage\UncompressedOrZlib
-PresentationContext194 = DRAFT_SRAudioStorage\UncompressedOrZlib
-PresentationContext195 = DRAFT_SRComprehensiveStorage\UncompressedOrZlib
-PresentationContext196 = DRAFT_SRDetailStorage\UncompressedOrZlib
-PresentationContext197 = DRAFT_SRTextStorage\UncompressedOrZlib
-PresentationContext198 = DRAFT_WaveformStorage\UncompressedOrZlib
+PresentationContext195 = DRAFT_RTBeamsDeliveryInstructionStorage\UncompressedOrZlib
+PresentationContext196 = DRAFT_SRAudioStorage\UncompressedOrZlib
+PresentationContext197 = DRAFT_SRComprehensiveStorage\UncompressedOrZlib
+PresentationContext198 = DRAFT_SRDetailStorage\UncompressedOrZlib
+PresentationContext199 = DRAFT_SRTextStorage\UncompressedOrZlib
+PresentationContext200 = DRAFT_WaveformStorage\UncompressedOrZlib
 #
 # DICOS Storage
 #
-PresentationContext199 = DICOS_CTImageStorage\AnyTransferSyntax
-PresentationContext200 = DICOS_DigitalXRayImageStorageForPresentation\AnyTransferSyntax
-PresentationContext201 = DICOS_DigitalXRayImageStorageForProcessing\AnyTransferSyntax
-PresentationContext202 = DICOS_2DAITStorage\AnyTransferSyntax
-PresentationContext203 = DICOS_3DAITStorage\AnyTransferSyntax
-PresentationContext204 = DICOS_QuadrupoleResonanceStorage\UncompressedOrZlib
-PresentationContext205 = DICOS_ThreatDetectionReportStorage\UncompressedOrZlib
+PresentationContext201 = DICOS_CTImageStorage\AnyTransferSyntax
+PresentationContext202 = DICOS_DigitalXRayImageStorageForPresentation\AnyTransferSyntax
+PresentationContext203 = DICOS_DigitalXRayImageStorageForProcessing\AnyTransferSyntax
+PresentationContext204 = DICOS_2DAITStorage\AnyTransferSyntax
+PresentationContext205 = DICOS_3DAITStorage\AnyTransferSyntax
+PresentationContext206 = DICOS_QuadrupoleResonanceStorage\UncompressedOrZlib
+PresentationContext207 = DICOS_ThreatDetectionReportStorage\UncompressedOrZlib
 #
 # DICONDE Storage
 #
-PresentationContext206 = DICONDE_EddyCurrentImageStorage\AnyTransferSyntax
-PresentationContext207 = DICONDE_EddyCurrentMultiframeImageStorage\AnyTransferSyntax
-PresentationContext208 = DICONDE_ThermographyImageStorage\AnyTransferSyntax
-PresentationContext209 = DICONDE_ThermographyMultiFrameImageStorage\AnyTransferSyntax
+PresentationContext208 = DICONDE_EddyCurrentImageStorage\AnyTransferSyntax
+PresentationContext209 = DICONDE_EddyCurrentMultiframeImageStorage\AnyTransferSyntax
+PresentationContext210 = DICONDE_ThermographyImageStorage\AnyTransferSyntax
+PresentationContext211 = DICONDE_ThermographyMultiFrameImageStorage\AnyTransferSyntax
+PresentationContext212 = DICONDE_UltrasoundWaveformStorage\UncompressedOrZlib
 
 # ----------------------------------------------------------------------------
 
@@ -631,7 +640,9 @@ PresentationContext128 = VideoPhotographicImageStorage\MPEG2
 # - VisualAcuityMeasurementsStorage
 # - VLWholeSlideMicroscopyImageStorage
 # - VolumeRenderingVolumetricPresentationStateStorage
+# - WaveformAcquisitionPresentationStateStorage
 # - WaveformAnnotationSRStorage
+# - WaveformPresentationStateStorage
 # - WideFieldOphthalmicPhotographyStereographicProjectionImageStorage
 # - WideFieldOphthalmicPhotography3DCoordinatesImageStorage
 # - XAPerformedProcedureProtocolStorage
@@ -665,6 +676,7 @@ PresentationContext128 = VideoPhotographicImageStorage\MPEG2
 # - DICONDE_EddyCurrentMultiframeImageStorage
 # - DICONDE_ThermographyImageStorage
 # - DICONDE_ThermographyMultiFrameImageStorage
+# - DICONDE_UltrasoundWaveformStorage
 
 # ============================================================================
 [[SCPSCURoleSelection]]
@@ -851,34 +863,37 @@ Role177 = TwelveLeadECGWaveformStorage\BOTH
 Role178 = VariableModalityLUTSoftcopyPresentationStateStorage\BOTH
 Role179 = VisualAcuityMeasurementsStorage\BOTH
 Role180 = VolumeRenderingVolumetricPresentationStateStorage\BOTH
-Role181 = WaveformAnnotationSRStorage\BOTH
-Role182 = XADefinedProcedureProtocolStorage\BOTH
-Role183 = XAPerformedProcedureProtocolStorage\BOTH
-Role184 = XAXRFGrayscaleSoftcopyPresentationStateStorage\BOTH
-Role185 = XRayRadiationDoseSRStorage\BOTH
-Role186 = RETIRED_StandaloneCurveStorage\BOTH
-Role187 = RETIRED_StandaloneModalityLUTStorage\BOTH
-Role188 = RETIRED_StandaloneOverlayStorage\BOTH
-Role189 = RETIRED_StandalonePETCurveStorage\BOTH
-Role190 = RETIRED_StandaloneVOILUTStorage\BOTH
-Role191 = RETIRED_StoredPrintStorage\BOTH
-Role192 = DRAFT_RTBeamsDeliveryInstructionStorage\BOTH
-Role193 = DRAFT_SRAudioStorage\BOTH
-Role194 = DRAFT_SRComprehensiveStorage\BOTH
-Role195 = DRAFT_SRDetailStorage\BOTH
-Role196 = DRAFT_SRTextStorage\BOTH
-Role197 = DRAFT_WaveformStorage\BOTH
-Role198 = DICOS_CTImageStorage\BOTH
-Role199 = DICOS_DigitalXRayImageStorageForPresentation\BOTH
-Role200 = DICOS_DigitalXRayImageStorageForProcessing\BOTH
-Role201 = DICOS_2DAITStorage\BOTH
-Role202 = DICOS_3DAITStorage\BOTH
-Role203 = DICOS_QuadrupoleResonanceStorage\BOTH
-Role204 = DICOS_ThreatDetectionReportStorage\BOTH
-Role205 = DICONDE_EddyCurrentImageStorage\BOTH
-Role206 = DICONDE_EddyCurrentMultiframeImageStorage\BOTH
-Role207 = DICONDE_ThermographyImageStorage\BOTH
-Role208 = DICONDE_ThermographyMultiFrameImageStorage\BOTH
+Role181 = WaveformAcquisitionPresentationStateStorage\BOTH
+Role182 = WaveformAnnotationSRStorage\BOTH
+Role183 = WaveformPresentationStateStorage\BOTH
+Role184 = XADefinedProcedureProtocolStorage\BOTH
+Role185 = XAPerformedProcedureProtocolStorage\BOTH
+Role186 = XAXRFGrayscaleSoftcopyPresentationStateStorage\BOTH
+Role187 = XRayRadiationDoseSRStorage\BOTH
+Role188 = RETIRED_StandaloneCurveStorage\BOTH
+Role189 = RETIRED_StandaloneModalityLUTStorage\BOTH
+Role190 = RETIRED_StandaloneOverlayStorage\BOTH
+Role191 = RETIRED_StandalonePETCurveStorage\BOTH
+Role192 = RETIRED_StandaloneVOILUTStorage\BOTH
+Role193 = RETIRED_StoredPrintStorage\BOTH
+Role194 = DRAFT_RTBeamsDeliveryInstructionStorage\BOTH
+Role195 = DRAFT_SRAudioStorage\BOTH
+Role196 = DRAFT_SRComprehensiveStorage\BOTH
+Role197 = DRAFT_SRDetailStorage\BOTH
+Role198 = DRAFT_SRTextStorage\BOTH
+Role199 = DRAFT_WaveformStorage\BOTH
+Role200 = DICOS_CTImageStorage\BOTH
+Role201 = DICOS_DigitalXRayImageStorageForPresentation\BOTH
+Role202 = DICOS_DigitalXRayImageStorageForProcessing\BOTH
+Role203 = DICOS_2DAITStorage\BOTH
+Role204 = DICOS_3DAITStorage\BOTH
+Role205 = DICOS_QuadrupoleResonanceStorage\BOTH
+Role206 = DICOS_ThreatDetectionReportStorage\BOTH
+Role207 = DICONDE_EddyCurrentImageStorage\BOTH
+Role208 = DICONDE_EddyCurrentMultiframeImageStorage\BOTH
+Role209 = DICONDE_ThermographyImageStorage\BOTH
+Role210 = DICONDE_ThermographyMultiFrameImageStorage\BOTH
+Role211 = DICONDE_UltrasoundWaveformStorage\BOTH
 
 # ============================================================================
 [[Profiles]]
index 538dae3c8de0742f1a25a8feabf03d705440f041..b47292f04b344827562062b61e17065a7abe974b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2018, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -46,6 +46,7 @@ public:
      *  @param assoc pointer to DIMSE association
      *  @param msgid DIMSE message ID
      *  @param pr DIMSE priority
+     *  @param secureConnect a flag indicating whether or not a secure connection was requested
      */
     DcmQueryRetrieveMoveContext(
       DcmQueryRetrieveDatabaseHandle& handle,
@@ -55,7 +56,8 @@ public:
       DIC_US priorstatus,
       T_ASC_Association *assoc,
       DIC_US msgid,
-      T_DIMSE_Priority pr)
+      T_DIMSE_Priority pr,
+      OFBool secureConnect)
     : dbHandle(handle)
     , options_(options)
     , associationConfiguration_(associationConfiguration)
@@ -75,6 +77,7 @@ public:
     , nCompleted(0)
     , nFailed(0)
     , nWarning(0)
+    , secureConnection(secureConnect)
     {
       origAETitle[0] = '\0';
       origHostName[0] = '\0';
@@ -183,6 +186,8 @@ private:
     /// number of completed sub-operations that causes warnings
     DIC_US nWarning;
 
+    /// a flag indicating whether or not a secure connection was requested
+    OFBool secureConnection;
 };
 
 #endif
index bc83777c01987711b9fc31fe620927ff8cfcb5f7..26dbdec505eaf87ad4bad3a15348009eff201b38 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2017, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -168,6 +168,10 @@ public:
 
   /// profile name for outgoing association configuration
   OFString outgoingProfile;
+
+  /// secure connection requested?
+  OFBool secureConnectionRequested_;
+
 };
 
 
index fee635b485e0becdfc471510476dc88d3dd298f5..ddd3305e01152ccfb8293485dff6b30eca2cfdf9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2021, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -33,9 +33,7 @@
 #include "dcmtk/ofstd/ofstd.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* needed on Solaris for O_RDONLY */
-#endif
 END_EXTERN_C
 
 static void getSubOpProgressCallback(void * /* callbackData */,
@@ -176,9 +174,9 @@ OFCondition DcmQueryRetrieveGetContext::performGetSubOp(DIC_UI sopClass, DIC_UI
     /* shared lock image file */
     int lockfd;
 #ifdef O_BINARY
-    lockfd = open(fname, O_RDONLY | O_BINARY, 0666);
+    lockfd = open(fname, O_RDONLY | O_BINARY);
 #else
-    lockfd = open(fname, O_RDONLY , 0666);
+    lockfd = open(fname, O_RDONLY);
 #endif
     if (lockfd < 0) {
         /* due to quota system the file could have been deleted */
index 9c954ae5c22bf2ff434586daf72e35defa770676..eb3903441fe6ae0960492cf08cc234dd9f492092 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2022, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -34,9 +34,7 @@
 #include "dcmtk/ofstd/ofstd.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* needed on Solaris for O_RDONLY */
-#endif
 END_EXTERN_C
 
 
@@ -201,9 +199,9 @@ OFCondition DcmQueryRetrieveMoveContext::performMoveSubOp(DIC_UI sopClass, DIC_U
     /* shared lock image file */
     int lockfd;
 #ifdef O_BINARY
-    lockfd = open(fname, O_RDONLY | O_BINARY, 0666);
+    lockfd = open(fname, O_RDONLY | O_BINARY);
 #else
-    lockfd = open(fname, O_RDONLY , 0666);
+    lockfd = open(fname, O_RDONLY);
 #endif
     if (lockfd < 0) {
         /* due to quota system the file could have been deleted */
@@ -317,6 +315,17 @@ OFCondition DcmQueryRetrieveMoveContext::buildSubAssociation(T_DIMSE_C_MoveRQ *r
             DCMQRDB_ERROR("moveSCP: Cannot create Association-params for sub-ops: " << DimseCondition::dump(temp_str, cond));
         }
     }
+
+    if (cond.good()) {
+        // use the same network protocol family for incoming and outgoing connections
+        ASC_setProtocolFamily(params, dcmIncomingProtocolFamily.get());
+
+        cond = ASC_setTransportLayerType(params, options_.secureConnectionRequested_);
+        if (cond.bad()) {
+            DCMQRDB_ERROR("moveSCP: Cannot create TLS transport layer for sub-ops: " << DimseCondition::dump(temp_str, cond));
+        }
+    }
+
     if (cond.good()) {
         OFStandard::snprintf(dstHostNamePlusPort, sizeof(DIC_NODENAME), "%s:%d", dstHostName, dstPortNumber);
         ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(),
@@ -331,6 +340,12 @@ OFCondition DcmQueryRetrieveMoveContext::buildSubAssociation(T_DIMSE_C_MoveRQ *r
         if (cond.bad()) {
             DCMQRDB_ERROR(DimseCondition::dump(temp_str, cond));
         }
+        else {
+            cond = ASC_setTransportLayerType(params, secureConnection);
+            if (cond.bad()) {
+                DCMQRDB_ERROR(DimseCondition::dump(temp_str, cond));
+            }
+        }
         DCMQRDB_DEBUG("Request Parameters:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_RQ));
     }
     if (cond.good()) {
@@ -352,6 +367,7 @@ OFCondition DcmQueryRetrieveMoveContext::buildSubAssociation(T_DIMSE_C_MoveRQ *r
     if (cond.good()) {
         assocStarted = OFTrue;
     }
+
     return cond;
 }
 
index 0a02f060a0ef03c1a1c3659f5c9b0378d29d60e5..ef2afb12bfb9ca5b91eabc818c8c1a090f75b989 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2024, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -295,8 +295,6 @@ void DcmQueryRetrieveConfig::panic(const char *fmt, ...)
 {
    va_list  ap;
    va_start(ap, fmt);
-
-#if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
    char buf[4096];
 
 #ifdef HAVE_PROTOTYPE_STD__VSNPRINTF
@@ -310,11 +308,6 @@ void DcmQueryRetrieveConfig::panic(const char *fmt, ...)
    buf[4095] = '\0';
 
    DCMQRDB_ERROR("CONFIG Error: " << buf << "!");
-#else
-   fprintf(stderr, "CONFIG Error: ");
-   vfprintf(stderr, fmt, ap);
-   fprintf(stderr, "!\n");
-#endif
    va_end(ap);
 }
 
index 132f8a115a5cd6d8ba4763581d15f1d032671f10..c91116a1c5171400a4dd3efe20e22a17eaec4131 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2024, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
@@ -72,7 +68,7 @@ static const DB_FindAttr TbFindAttr [] = {
         DB_FindAttr( DCM_PatientBirthTime,                      PATIENT_LEVEL,  OPTIONAL_KEY ),
         DB_FindAttr( DCM_RETIRED_OtherPatientIDs,               PATIENT_LEVEL,  OPTIONAL_KEY ),
         DB_FindAttr( DCM_OtherPatientNames,                     PATIENT_LEVEL,  OPTIONAL_KEY ),
-        DB_FindAttr( DCM_EthnicGroup,                           PATIENT_LEVEL,  OPTIONAL_KEY ),
+        DB_FindAttr( DCM_RETIRED_EthnicGroup,                   PATIENT_LEVEL,  OPTIONAL_KEY ),
         DB_FindAttr( DCM_PatientComments,                       PATIENT_LEVEL,  OPTIONAL_KEY ),
         DB_FindAttr( DCM_IssuerOfPatientID,                     PATIENT_LEVEL,  OPTIONAL_KEY ),
         DB_FindAttr( DCM_StudyDate,                             STUDY_LEVEL,    REQUIRED_KEY ),
@@ -210,7 +206,7 @@ static void DB_IdxInitRecord (IdxRecord *idx, int linksOnly)
         idx -> param[RECORDIDX_OtherPatientNames]. XTag = DCM_OtherPatientNames ;
         idx -> param[RECORDIDX_OtherPatientNames]. ValueLength = PN_MAX_LENGTH ;
         idx -> OtherPatientNames[0] = '\0' ;
-        idx -> param[RECORDIDX_EthnicGroup]. XTag = DCM_EthnicGroup ;
+        idx -> param[RECORDIDX_EthnicGroup]. XTag = DCM_RETIRED_EthnicGroup ;
         idx -> param[RECORDIDX_EthnicGroup]. ValueLength = SH_MAX_LENGTH ;
         idx -> EthnicGroup[0] = '\0' ;
         idx -> param[RECORDIDX_StudyDate]. XTag = DCM_StudyDate ;
@@ -1381,8 +1377,10 @@ OFCondition DcmQueryRetrieveIndexDatabaseHandle::startFindRequest(
                 /* only char string type tags are supported at the moment */
                 char *s = NULL;
                 dcelem->getString(s);
+
                 /* the available space is always elem.ValueLength+1 */
-                OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
+                if (s) OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
+                    else elem.PValueField[0]='\0';
             }
             /** If element is the Query Level, store it in handle
              */
@@ -2066,8 +2064,10 @@ OFCondition DcmQueryRetrieveIndexDatabaseHandle::startMoveRequest(
                 /* only char string type tags are supported at the moment */
                 char *s = NULL;
                 dcelem->getString(s);
+
                 /* the available space is always elem.ValueLength+1 */
-                OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
+                if (s) OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
+                    else elem.PValueField[0]='\0';
             }
 
             /** If element is the Query Level, store it in handle
@@ -2359,9 +2359,9 @@ OFCondition DcmQueryRetrieveIndexDatabaseHandle::deleteImageFile(char* imgFile)
 #ifdef LOCK_IMAGE_FILES
     int lockfd;
 #ifdef O_BINARY
-    lockfd = open(imgFile, O_RDWR | O_BINARY, 0666);    /* obtain file descriptor */
+    lockfd = open(imgFile, O_RDWR | O_BINARY);    /* obtain file descriptor */
 #else
-    lockfd = open(imgFile, O_RDWR, 0666);   /* obtain file descriptor */
+    lockfd = open(imgFile, O_RDWR);   /* obtain file descriptor */
 #endif
     if (lockfd < 0) {
       DCMQRDB_WARN("DB ERROR: cannot open image file for deleting: " << imgFile);
index 31ddffb85e62cb3ff01cdf49885b1f62e3537fc4..877aedaeca5c8736a4e747f90ceb74a89b503c22 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2021, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -71,6 +71,7 @@ DcmQueryRetrieveOptions::DcmQueryRetrieveOptions()
 , associationConfigFile()
 , incomingProfile()
 , outgoingProfile()
+, secureConnectionRequested_(OFFalse)
 {
 }
 
index 4c450c2842ef9dee628222c042569db2a7c11314..97453e9761d174d7fe1c3f966cee91935e80439b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2024, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -323,7 +323,8 @@ OFCondition DcmQueryRetrieveSCP::moveSCP(T_ASC_Association * assoc, T_DIMSE_C_Mo
         T_ASC_PresentationContextID presID, DcmQueryRetrieveDatabaseHandle& dbHandle)
 {
     OFCondition cond = EC_Normal;
-    DcmQueryRetrieveMoveContext context(dbHandle, options_, associationConfiguration_, config_, STATUS_Pending, assoc, request->MessageID, request->Priority);
+    DcmQueryRetrieveMoveContext context(dbHandle, options_, associationConfiguration_, config_, STATUS_Pending, assoc, request->MessageID, request->Priority,
+        tlsOptions_.secureConnectionRequested());
 
     DIC_AE aeTitle;
     aeTitle[0] = '\0';
index 30f309f7f58bf5a0028b8f4ad9b7b00461fcf06e..b0ecef8348e57d420d3576f27dc242b7a075baf2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1993-2024, OFFIS e.V.
+ *  Copyright (C) 1993-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* needed for stat() */
-#endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* needed on Solaris for O_RDONLY */
-#endif
 END_EXTERN_C
 
 /* ========================================== helper functions ======================================== */
@@ -779,9 +775,9 @@ OFBool DcmQueryRetrieveTelnetInitiator::TI_storeImage(char *sopClass, char *sopI
      /* shared lock image file */
     int lockfd;
 #ifdef O_BINARY
-    lockfd = open(imgFile, O_RDONLY | O_BINARY, 0666);
+    lockfd = open(imgFile, O_RDONLY | O_BINARY);
 #else
-    lockfd = open(imgFile, O_RDONLY, 0666);
+    lockfd = open(imgFile, O_RDONLY);
 #endif
     if (lockfd < 0) {
         DCMQRDB_WARN("CTN has deleted image, giving up (no imgFile): "
index ad990ea0bb829915c90784de2cf3b7587fdd494d..24b723d96df25cf0c0876c7817c93666779a63d0 100644 (file)
@@ -2,4 +2,4 @@
 DCMTK_ADD_EXECUTABLE(drtdump drtdump.cc)
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(drtdump dcmrt dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(drtdump dcmrt)
index 0796f417570b0ab58bb50f772f9f73eb13e47970..75fc4b923f9e8b9c05e15a4c9e62ceae414644c8 100644 (file)
@@ -181,7 +181,7 @@ It is an error if no data dictionary can be loaded.
 
 \section drtdump_copyright COPYRIGHT
 
-Copyright (C) 2010-2024 by OFFIS e.V. and ICSMED AG, Escherweg 2, 26121
+Copyright (C) 2010-2025 by OFFIS e.V. and ICSMED AG, Escherweg 2, 26121
 Oldenburg, Germany.
 
 */
index a4e7c65dbf573d8c714f228745be70bdd0b21511..a65b8f8f79a41f5db0c7485ad5ed12bb2c99c142 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *
  *  Copyright (c) 2008-2012, OFFIS e.V. and ICSMED AG, Oldenburg, Germany
- *  Copyright (C) 2013-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2013-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class DRTTypes
@@ -50,7 +50,7 @@
  *  These error codes can be used in addition to the general purpose
  *  codes defined in module dcmdata.
  */
-//@{
+///@{
 
 /// error: a value is invalid according to the standard
 extern DCMTK_DCMRT_EXPORT const OFConditionConst RT_EC_InvalidValue;
@@ -61,7 +61,7 @@ extern DCMTK_DCMRT_EXPORT const OFConditionConst RT_EC_UnsupportedValue;
 /// error: the object is invalid, see isValid() method in IOD class
 extern DCMTK_DCMRT_EXPORT const OFConditionConst RT_EC_InvalidObject;
 
-//@}
+///@}
 
 
 // global definitions for logging mechanism provided by the oflog module
index a2a7b08e4a66b70a75c8592daf81a97f859f00b0..f2829f521c3c0a0926eba1021a72a4a889d49b33 100644 (file)
@@ -34,7 +34,7 @@ DRTDoseIOD::DRTDoseIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index 62478c8980d7c15279cb512b3e89e01b090b1db3..14ca202072fde87a8c16b2d7b90008db58618314 100644 (file)
@@ -34,7 +34,7 @@ DRTImageIOD::DRTImageIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index 4503ddad2be165259fc9e994f1f0818a5fb824ce..c723c6656b63671c306bcf2badff22b889c5a075 100644 (file)
@@ -34,7 +34,7 @@ DRTIonPlanIOD::DRTIonPlanIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index 7ff9c56e1364fbe6307b612ef1457e01c81a5970..eb4e6e4a24a4ea74fa09bfb84db1fc4230694ed7 100644 (file)
@@ -34,7 +34,7 @@ DRTIonBeamsTreatmentRecordIOD::DRTIonBeamsTreatmentRecordIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index 1c47f8fdb1be13ac0572d77c991a9bbc5aa08a4f..ac44857e11553d3d818a44ba44f399b4dd3b31e0 100644 (file)
@@ -34,7 +34,7 @@ DRTPlanIOD::DRTPlanIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index 6670863f3e34bd186f819d7c39064663385c996d..3089781228a37de42013f064ae9920d8e598d2c3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *
  *  Copyright (C) 2008-2012, OFFIS e.V. and ICSMED AG, Oldenburg, Germany
- *  Copyright (C) 2013-2023, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2013-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class DRTStructureSetIOD
@@ -34,7 +34,7 @@ DRTStructureSetIOD::DRTStructureSetIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index ea37dce608219aa9685e8814f0c46929475322b1..99982848095655b1d6a58a177d2b256d60fd50af 100644 (file)
@@ -34,7 +34,7 @@ DRTTreatmentSummaryRecordIOD::DRTTreatmentSummaryRecordIOD()
     PatientBirthTime(DCM_PatientBirthTime),
     OtherPatientIDsSequence(),
     OtherPatientNames(DCM_OtherPatientNames),
-    EthnicGroup(DCM_EthnicGroup),
+    EthnicGroup(DCM_RETIRED_EthnicGroup),
     PatientComments(DCM_PatientComments),
     PatientSpeciesDescription(DCM_PatientSpeciesDescription),
     PatientSpeciesCodeSequence(),
index dc4e0d008c1a7b3c5cc1741ab30762fe9ac3809d..d06b07545c2a801f89bdb020fdcb08b08731f92c 100644 (file)
@@ -7,8 +7,8 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmrt_tests
 )
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(drttest dcmrt dcmdata oflog ofstd)
-DCMTK_TARGET_LINK_MODULES(dcmrt_tests dcmrt dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(drttest dcmrt)
+DCMTK_TARGET_LINK_MODULES(dcmrt_tests dcmrt)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmrt)
index f1c79ee8752d8d6dd52b86dae232752e858aa9fc..b2be6158fd9185e8689580f28f675c5fff6a4be9 100644 (file)
@@ -36,6 +36,7 @@ include-all:
 libsrc-all: include-all
        (cd libsrc && $(MAKE) ARCH="$(ARCH)" all)
 
+
 tests-all: libsrc-all
        (cd tests && $(MAKE) ARCH="$(ARCH)" all)
 
@@ -67,18 +68,12 @@ clean:
        (cd include && $(MAKE) clean)
        (cd libsrc && $(MAKE) clean)
        (cd tests && $(MAKE) clean)
-       (cd docs && $(MAKE) clean)
-       (cd data && $(MAKE) clean)
-       (cd etc && $(MAKE) clean)
        rm -f $(TRASH)
 
 distclean:
        (cd include && $(MAKE) distclean)
        (cd libsrc && $(MAKE) distclean)
        (cd tests && $(MAKE) distclean)
-       (cd docs && $(MAKE) distclean)
-       (cd data && $(MAKE) distclean)
-       (cd etc && $(MAKE) distclean)
        rm -f $(DISTTRASH)
 
 dependencies:
diff --git a/dcmseg/include/dcmtk/dcmseg/overlaputil.h b/dcmseg/include/dcmtk/dcmseg/overlaputil.h
new file mode 100644 (file)
index 0000000..54a9009
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ *
+ *  Copyright (C) 2023-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmqi
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Interface of class OverlapUtil
+ *
+ */
+
+#ifndef OVERLAPUTIL_H
+#define OVERLAPUTIL_H
+
+#include "dcmtk/dcmiod/iodtypes.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/ofstd/oftypes.h"
+#include "dcmtk/ofstd/ofvector.h"
+
+class DcmSegmentation;
+
+/** Class that analyzes the frame-based segment structures of a given segmentation object.
+ *  It provides the following main functionality:
+ *  - Grouping of "physical" frames by their position in space (called "logical frames"), i.e.
+ *    frames that are at the same position in space are grouped together.
+ *  - For every logical frame (i.e. position in space), it lists the segments found at this
+ *    position together with their respective physical frame number
+ *  - Return physical frame numbers for a given segment number
+ *  - Building an overlap matrix that stores for each arbitrary segment pair whether
+ *    they overlap or not.
+ *  - Return groups of segments, that no two overlapping segments will be in the same group.
+ *    This will not necessarily return the optimal solution, but a solution that should be good enough.
+ *    For the method used see getNonOverlappingSegments().
+ */
+class OverlapUtil
+{
+public:
+    /// Image Position Patient tuple (x,y,z)
+    typedef OFVector<Float64> ImagePosition; // might be defined in respective functional group
+
+    /// Physical Frame number with its respective position
+    struct FramePositionAndNumber
+    {
+        /** Default constructor required for vector initialization
+         */
+        FramePositionAndNumber()
+            : m_position()
+            , m_frameNumber(0)
+        {
+        }
+        /** Constructor
+         *  @param  pos Image position
+         *   @param  num Physical frame number
+         */
+        FramePositionAndNumber(const ImagePosition& pos, const Uint32& num)
+            : m_position(pos)
+            , m_frameNumber(num)
+        {
+        }
+        /// Frame position in space
+        ImagePosition m_position;
+        /// Physical frame number (number of frame in DICOM object)
+        Uint32 m_frameNumber;
+    };
+
+    /// Physical Frame number with its respective position
+    typedef OFVector<FramePositionAndNumber> FramePositions;
+
+    /// Logical Frame, represented and defined by various physical frames (numbers) at the same position
+    typedef OFVector<Uint32> LogicalFrame;
+
+    /// All distinct positions and for each position the physical frame numbers that can be found at it
+    typedef OFVector<LogicalFrame> DistinctFramePositions;
+
+    /// Lists frames for each segment where segment with index i is represented by the vector at index i,
+    /// and index 0 is unused. I.e. index i is segment number, value is vector of physical frame numbers.
+    typedef OFVector<OFVector<Uint32> > FramesForSegment;
+
+    /// Implements comparision operator to be used for sorting of frame positions,
+    /// making the sorting order depend on the coordinate given in the constructor
+    struct ComparePositions
+    {
+        /** Constructor, used to configure coordinate position to be used for sorting
+         *  @param  c Coordinate position to be used for sorting
+         */
+        ComparePositions(size_t c)
+            : m_coordinate(c)
+        {
+        }
+
+        /** Compare two frames
+         *  @param  a First frame to compare
+         *  @param  b Second frame to compare
+         *  @return Returns true if a is less than b based on the coordinate used for sorting
+         */
+        bool operator()(const FramePositionAndNumber& a, const FramePositionAndNumber& b) const
+        {
+            return a.m_position[m_coordinate] < b.m_position[m_coordinate];
+        }
+        /// Coordinate position (0-2, i.e. x,x,z) to be used for sorting
+        size_t m_coordinate;
+    };
+
+    /// Matrix of N x N segment numbers, where N is the number of segments.
+    /// Value is 1 at x,y if x and y overlap, 0 if they don't overlap, and -1 if not initialized.
+    typedef OFVector<OFVector<Sint8> > OverlapMatrix;
+
+    /// Group of non-overlapping segments (each represented by its segment number)
+    typedef OFVector<OFVector<Uint32> > SegmentGroups;
+
+    /** Represents a segment number and a logical frame number it is found at
+     */
+    struct SegNumAndFrameNum
+    {
+        /** Constructor
+         *  @param  s Segment number
+         *  @param  f Logical frame number
+         */
+        SegNumAndFrameNum(const Uint16 s, const Uint32 f)
+            : m_segmentNumber(s)
+            , m_frameNumber(f)
+        {
+        }
+        /** Default constructor
+         */
+        SegNumAndFrameNum()
+            : m_segmentNumber(0)
+            , m_frameNumber(0)
+        {
+        }
+
+        /// Segment number as used in DICOM segmentation object (1-n)
+        Uint16 m_segmentNumber;
+        /// Logical frame number (number of frame in DistinctFramePositions vector)
+        Uint32 m_frameNumber;
+    };
+
+    /// Segments and their phyiscal frame number (inner set), grouped by their
+    /// respective logical frame number (outer vector) .The inner vector is not
+    // sorted by segment number but will uniquely contain each segment only once.
+    // A std::set would be more appropriate, but since this is not supported by all
+    // compilers used for DCMTK, we use a vector and check for duplicates manually.
+    typedef OFVector<OFVector<SegNumAndFrameNum> > SegmentsByPosition;
+
+    // ------------------------------------------ Methods ------------------------------------------
+
+    /** Constructor. Use setSegmentationObject() to set the segmentation object to work with.
+     */
+    OverlapUtil();
+
+    /** Destructor */
+    ~OverlapUtil();
+
+    /** Set the segmentation object to work with and clears all old data.
+     *  @param  seg The segmentation object to work with (not owned by this class)
+     */
+    void setSegmentationObject(DcmSegmentation* seg);
+
+    /** Clears all internal data (except segmentation object reference).
+     *  This should be called whenever the input data (i.e. the underlying)
+     *  DICOM segmentation object changes, before calling any other method.
+     */
+    void clear();
+
+    /** Get all distinct frame positions and the physical frame numbers at this position
+     *  @param  result Resulting vector of distinct frame positions
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition getFramesByPosition(DistinctFramePositions& result);
+
+    /** Get all segments and their physical frame number, grouped by their respective logical frame number
+     *  @param  result Resulting vector of segments grouped by logical frame number
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition getSegmentsByPosition(SegmentsByPosition& result);
+
+    /** Get phyiscal frames for a specific segment by its segment number
+     *  @param segmentNumber Segment number to get frames for (1..n)
+     *  @param frames Resulting vector of physical frame numbers (first frame is frame 0)
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition getFramesForSegment(const Uint32 segmentNumber, OFVector<Uint32>& frames);
+
+    /** Returns computed overlap matrix
+     *  @param  matrix Resulting overlap matrix
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition getOverlapMatrix(OverlapMatrix& matrix);
+
+    /** Returns segments grouped together in a way, that no two overlapping
+     *  segments will be in the same group. This method does not necessarily
+     *  returns the optimal solution, but a solution that should be good enough.
+     *  It is guaranteed, that segments in the same group don't overlap.
+     *
+     *  It is based on the idea of a greedy algorithm  that creates a first group
+     *  containing the first segment. Then it goes to the next segment, checks whether
+     *  it fits into the first group with no overlaps (easily checked in overlap matrix)
+     *  and inserts it into that group if no overlaps exists. Otherwise, it creates a
+     *  new group and continues with the next segment (trying to insert it into
+     *  the first group, then second group, otherwise creates third group, and so on).
+     *  @param  segmentGroups Resulting vector of segment groups, each listing the
+     *          segment numbers that are in that group
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition getNonOverlappingSegments(SegmentGroups& segmentGroups);
+
+    /** Prints segments by their position in space
+     * @param  ss The stream to dump to
+     */
+    void printSegmentsByPosition(OFStringStream& ss);
+
+    /** Prints segment overlap matrix to given stream
+     *  @param  ss The stream to dump to
+     */
+    void printOverlapMatrix(OFStringStream& ss);
+
+    /** Prints groups of non-overlapping segments (identified by their numbers)
+     *  to given stream
+     *  @param  ss The stream to dump to
+     */
+    void printNonOverlappingSegments(OFStringStream& ss);
+
+    /** Return whether there are at least two segments, that overlap each other.
+     *  The overlap matrix is used (and computed if not already done) for this purpose.
+     *  @return True if overlapping segments exist, false otherwise
+     */
+    OFBool hasOverlappingSegments();
+
+    /** Returns the absolute value of a floating-point number
+     *  @param value The input value
+     *  @return The absolute value of the input
+     */
+    static Float64 fabs(const Float64 value);
+
+protected:
+
+
+    /** Group physical frame positions into logical positions. This is done by sorting
+     *  frames after *that* position coordinate that in its mean position difference is
+     *  larger than slice thickness * 0.9. Then those frames  that are close enough to
+     *  each other (i.e. distance is smaller than slice thickness * 0.01), end up at the
+     *  same logical position (considered a "logical frame")
+     *  TODO: This should probably not use mean values for the coordinates
+     *  since in some cases, the mean difference in a slice coordinate might be close to 0
+     *  if many frames are at the same position. Instead, the maximum difference, variance or
+     *  something else could be used?
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition groupFramesByLogicalPosition();
+
+    /** Builds the overlap matrix, if not already done.
+     *  @return EC_Normal if successful or already existant, error otherwise
+     */
+    OFCondition buildOverlapMatrix();
+
+    /** Checks if frames are parallel, i.e. if DICOM Image Position Patient is present and
+     *  all frames are parallel to each other (i.e. found in the shared functional group)
+     *  @return EC_Normal if parallel, SG_EC_FramesNotParallel if image orientation is not shared,
+     *          error otherwise
+     */
+    OFCondition ensureFramesAreParallel();
+
+    /** Groups all physical frames by their position. This also works if the physical frames
+     *  have slightly different positions, i.e. if they are not exactly the same and are only
+     *  "close enough" to be considered the same. Right now, the maximum distance treated equal
+     *  is if distance is smaller than slice thickness * 0.01 (i.e. 1% of slice thickness).
+     *  Only performs the computation, if not done before.
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition groupFramesByPosition();
+
+    /** Checks whether the given two frames overlap
+     *  @param f1 Frame 1, provided by its physical frame number
+     *  @param f2 Frame 2, provided by its physical frame number
+     *  @param overlap Resulting overlap (overlaps if OFTrue, otherwise not)
+     *  @return EC_Normal if successful, error otherwise
+     */
+    OFCondition checkFramesOverlap(const Uint32& f1, const Uint32& f2, OFBool& overlap);
+
+    /** Checks whether the given two frames overlap by using comparing their pixel data
+     *  by bitwise "and". This is very efficient, however, only works and is called (right now),
+     *  if row*cols % 8 = 0, so we can easily extract frames as binary bitsets without unpacking them.
+     *  TODO: Check whether this can be easily extended to other cases as well.
+     *  @param  f1 Frame 1, provided by its physical frame number
+     *  @param  f2 Frame 2, provided by its physical frame number
+     *  @param  f1_data Pixel data of frame 1
+     *  @param  f2_data Pixel data of frame 2
+     *  @param  rows Number of rows of the frame(s), not used right now
+     *  @param  cols Number of columns of the frame(s), not used right now
+     *  @param  overlap Resulting overlap (overlaps if OFTrue, otherwise not)
+     *  @return EC_Normal if successful, error otherwise
+     */
+    static OFCondition checkFramesOverlapBinary(const Uint32& f1,
+                                         const Uint32& f2,
+                                         const DcmIODTypes::Frame<Uint8>* f1_data,
+                                         const DcmIODTypes::Frame<Uint8>* f2_data,
+                                         const Uint16& /* rows */,
+                                         const Uint16& /* cols */,
+                                         OFBool& overlap);
+
+    /** Checks whether the given two frames overlap by using comparing their pixel data
+     *  after unpacking, i.e. expanding every bit to a byte, and then comparing whether the two
+     *  related bytes of each frame are both non-zero. This is less efficient than checkFramesOverlapBinary(),
+     *  @param  f1 Frame 1, provided by its physical frame number
+     *  @param  f2 Frame 2, provided by its physical frame number
+     *  @param  f1_data Pixel data of frame 1
+     *  @param  f2_data Pixel data of frame 2
+     *  @param  rows Number of rows of the frame(s)
+     *  @param  cols Number of columns of the frame(s)
+     *  @param  overlap Resulting overlap (overlaps if OFTrue, otherwise not)
+     *  @return EC_Normal if successful, error otherwise
+     */
+    static OFCondition checkFramesOverlapUnpacked(const Uint32& f1,
+                                           const Uint32& f2,
+                                           const DcmIODTypes::Frame<Uint8>* f1_data,
+                                           const DcmIODTypes::Frame<Uint8>* f2_data,
+                                           const Uint16& rows,
+                                           const Uint16 cols,
+                                           OFBool& overlap);
+
+    /** Return the most relevant (changing) coordinate, computed by multiplying
+     *  x and y vectors of the image orientation and selecting the coordinate
+     *  with the largest absolute value.
+     *  @param  imageOrientation Image orientation patient (3 coordinates for x vector,
+     *  3 coordinates for y vector )
+     *  @return 0 if x, 1 if y, 2 if z, 3 if not determinable
+     */
+    static Uint8 identifyChangingCoordinate(const OFVector<Float64>& imageOrientation);
+
+private:
+    /// Image Orientation Patient
+    OFVector<Float64> m_imageOrientation;
+
+    /// Phyiscal frames with their respective positions (IPP)
+    FramePositions m_framePositions;
+
+    /// Outer vector with one entry per segment. Index is the DICOM segment
+    /// number where segment 1 goes to index 0, segment 2 to index 1, and so on.
+    /// Inner vector contains the physical frame numbers that represent the
+    /// segment.
+    FramesForSegment m_framesForSegment;
+
+    /// Logical frames, ie. physical frames with the same position are
+    /// grouped together to a logical frame. For every logical frame, we
+    /// store the related physical frame numbers. The logical frame number
+    /// is implicitly given by the index in the vector.
+    DistinctFramePositions m_logicalFramePositions;
+
+    /// Stores for each logical frame a collection of (paired) segment and
+    /// physical frame number, that exists at that position.
+    SegmentsByPosition m_segmentsByPosition;
+
+    /// Matrix that stores for each segment pair whether they overlap or not.
+    /// I.e. Matrix has size N x N, where N is the number of segments.
+    /// The diagonal is always 0 (no overlap), i.e. a segment never overlaps with itself.
+    /// If there is an overlap, the value is 1.
+    /// If the field is not initialized, the value is -1.
+    OverlapMatrix m_segmentOverlapMatrix;
+
+    //// Groups of segments that do not overlap with each other
+    SegmentGroups m_nonOverlappingSegments;
+
+    /// Reference to segmentation object to work with
+    /// Must be freed outside this class.
+    DcmSegmentation* m_seg;
+};
+
+#endif // OVERLAPUTIL_H
+
index 5a75e1e422ffd688b063d8e12db0e5062045c43b..c62aae492909d95e2ea1581f64245f619d8e1e50 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 #include "dcmtk/dcmfg/concatenationcreator.h" // for writing concatenations
 #include "dcmtk/dcmfg/concatenationloader.h"  // for loading concatenations
 #include "dcmtk/dcmfg/fginterface.h"          // for multi-frame functional group interface
+#include "dcmtk/dcmfg/fgseg.h"                // for FGSegmentation class
 #include "dcmtk/dcmiod/iodimage.h"            // common image IOD attribute access
-#include "dcmtk/dcmiod/iodmacro.h"
-#include "dcmtk/dcmiod/modenhequipment.h" // for enhanced general equipment module
-#include "dcmtk/dcmiod/modimagepixel.h"
+#include "dcmtk/dcmiod/iodmacro.h"            // various macros
+#include "dcmtk/dcmiod/modenhequipment.h"     // for enhanced general equipment module
+#include "dcmtk/dcmiod/modimagepixel.h"       //  for image pixel module
 #include "dcmtk/dcmiod/modmultiframedimension.h" // for multi-frame dimension module
+#include "dcmtk/dcmiod/modiccprofile.h"          // for ICC profile module
 #include "dcmtk/dcmiod/modmultiframefg.h"        // for multi-frame functional group module
 #include "dcmtk/dcmiod/modsegmentationseries.h"  // for segmentation series module
-#include "dcmtk/dcmseg/segdef.h"
+#include "dcmtk/dcmiod/modpalettecolorlut.h"     // for palette color LUT module
+#include "dcmtk/dcmseg/segdef.h"   //for definitions
+#include "dcmtk/dcmseg/segment.h"  // for DcmSegment class
 #include "dcmtk/dcmseg/segtypes.h" // for segmentation data types
-#include "dcmtk/ofstd/ofvector.h"  // for OFVector
+#include "dcmtk/dcmseg/segutils.h" // fo packBinaryFrame()
+#include "dcmtk/ofstd/ofvector.h"  // for OFVector class
+#include "dcmtk/ofstd/ofdiag.h"    // for DCMTK_DIAGNOSTIC_PUSH etc.
 
-// Forward declarations
-class DcmSegment;
 class FGSegmentation;
 class FGDerivationImage;
 class DcmFileFormat;
 
-/** Class representing an object of the "Segmentation SOP Class".
+/** Class representing an object of the "Segmentation IOD"
+ *  or "Label Map Segmentation IOD".
  */
-class DCMTK_DCMSEG_EXPORT DcmSegmentation : public DcmIODImage<IODImagePixelModule<Uint8> >
+
+class DCMTK_DCMSEG_EXPORT DcmSegmentation : public DcmIODImage<IODImagePixelModule<Uint16>, IODImagePixelModule<Uint8> >
 {
 
 public:
+
+    struct LoadingFlags;
+
     // -------------------- destruction -------------------------------
 
     /** Destructor, frees memory
@@ -65,9 +74,21 @@ public:
      *  @param  filename The file to read from
      *  @param  segmentation  The resulting segmentation object. NULL if dataset
      *          could not be read successfully.
+     *  @param  flags Flags to configure the loading of the segmentation object
+     *  @return EC_Normal if reading was successful, error otherwise
+     */
+    static OFCondition loadFile(const OFString& filename, DcmSegmentation*& segmentation, const DcmSegmentation::LoadingFlags& flags = LoadingFlags());
+
+    /** Static method to load a Segmentation object from a file.
+     *  The memory of the resulting Segmentation object has to be freed by the
+     *  caller.
+     *  @param  filename The file to read from
+     *  @param  segmentation  The resulting segmentation object. NULL if dataset
+     *          could not be read successfully.
+     *  @param  flags Flags to configure the loading of the segmentation object
      *  @return EC_Normal if reading was successful, error otherwise
      */
-    static OFCondition loadFile(const OFString& filename, DcmSegmentation*& segmentation);
+    static OFCondition loadFile(const OFFile& filename, DcmSegmentation*& segmentation, const DcmSegmentation::LoadingFlags& flags = LoadingFlags());
 
     /** Static method to load a Segmentation object from a dataset object.
      *  The memory of the resulting Segmentation object has to be freed by the
@@ -75,9 +96,10 @@ public:
      *  @param  dataset The dataset to read from
      *  @param  segmentation  The resulting segmentation object. NULL if dataset
      *          could not be read successfully.
+     *  @param  flags Flags to configure the loading of the segmentation object
      *  @return EC_Normal if reading was successful, error otherwise
      */
-    static OFCondition loadDataset(DcmDataset& dataset, DcmSegmentation*& segmentation);
+    static OFCondition loadDataset(DcmDataset& dataset, DcmSegmentation*& segmentation, const DcmSegmentation::LoadingFlags& flags = LoadingFlags());
 
     /** Static method to load a concatenation of a DICOM Segmentation instance
      *  into a DcmSegmentation object.
@@ -130,6 +152,16 @@ public:
      */
     virtual OFBool getCheckFGOnWrite();
 
+    /** Set whether attribute values should be checked on writing, i.e. if writing
+     *  should fail if attribute values violate their VR, VM, character set or value length.
+     *  A missing but required value is always considered an error, independent of this setting.
+     *  If set to OFFalse, writing will always succeed, even if attribute value constraints
+     *  are violated. A warning instead of an error will be printed to the logger.
+     *  @param  doCheck If OFTrue, attribute value errors are handled as errors on writing, if OFFalse
+     *          any errors are ignored.
+     */
+    virtual void setValueCheckOnWrite(const OFBool doCheck);
+
     /** If enabled, dimensions are checked before actual writing.
      *  This can be very time-consuming if many frames are present.
      *  Disabling should only be done if the user knows that the functional groups
@@ -147,6 +179,14 @@ public:
      */
     virtual OFBool getCheckDimensionsOnWrite();
 
+    /** Get input transfer syntax. Returns EXS_Unknown if object has been
+     *  created from scratch (and not from file or dataset).  If the
+     *  segmentation has been loaded from a concatenation, the value
+     *  will be EXS_Unknown.
+     *  @return Input transfer syntax
+     */
+    virtual E_TransferSyntax getInputTransferSyntax() const;
+
     // -------------------- creation ---------------------
 
     /** Factory method to create a binary segmentation object from the minimal
@@ -170,6 +210,35 @@ public:
                                                 const IODGeneralEquipmentModule::EquipmentInfo& equipmentInfo,
                                                 const ContentIdentificationMacro& contentIdentification);
 
+    /** Factory method to create a labelmap segmentation object from the minimal
+     *  set of information required. The actual segments and the frame data is
+     *  added separately.
+     *  The memory of the resulting Segmentation object has to be freed by the
+     *  caller.
+     *  @param  segmentation The resulting segmentation object if provided data is
+     *          valid. Otherwise NULL is returned.
+     *  @param  rows Number of rows of segmentation frame data
+     *  @param  columns Number of rows of segmentation frame data
+     *  @param  equipmentInfo Equipment that is responsible for creating the
+     *          segmentation. All attributes in equipmentInfo must have
+     *          non-empty values.
+     *  @param  contentIdentification Basic content identification information
+     *  @param  use16Bit Denote whether to use 16 bit pixel data, i.e
+     *          allow for more than 255 segments (labels) in the segmentation
+     *          object (up to 65535). If OFTrue, 16 bit pixel data is used,
+     *          otherwise 8 bit.
+     *  @param  colorModel The color model to be used for the labelmap. Default
+     *          is MONOCHROME2, alternative is PALETTE.
+     *  @return EC_Normal if creation was successful, error otherwise
+     */
+    static OFCondition createLabelmapSegmentation(DcmSegmentation*& segmentation,
+                                                  const Uint16 rows,
+                                                  const Uint16 columns,
+                                                  const IODGeneralEquipmentModule::EquipmentInfo& equipmentInfo,
+                                                  const ContentIdentificationMacro& contentIdentification,
+                                                  const OFBool use16Bit,
+                                                  const DcmSegTypes::E_SegmentationLabelmapColorModel colorModel = DcmSegTypes::SLCM_MONOCHROME2);
+
     /** Factory method to create a fractional segmentation object from the minimal
      *  set of information required. The actual segments and the frame data is
      *  added separately.
@@ -210,6 +279,12 @@ public:
 
     // -------------------- access ---------------------
 
+    OFBool has16BitPixelData() const;
+
+    Uint16 getRows();
+
+    Uint16 getColumns();
+
     /** Get number of frames, based on the number of items in the shared
      *  functional functional groups sequence (i.e.\ the attribute Number of
      *  Frames) is not trusted). Note that this returns the numbers of frames
@@ -288,7 +363,12 @@ public:
      *  @param  segmentNumber The logical segment number
      *  @return The segment if segment number is valid, NULL otherwise
      */
-    virtual DcmSegment* getSegment(const size_t segmentNumber);
+    virtual DcmSegment* getSegment(const Uint16 segmentNumber);
+
+    /** Get all segments
+     *  @return  The resulting segments
+     */
+    virtual const OFMap<Uint16, DcmSegment*>& getSegments();
 
     /** Get logical segment number by providing a pointer to a given segment
      *  @param  segment The segment to find the logical segment number for
@@ -308,7 +388,7 @@ public:
      *  @param  frameNo The number of the frame to get (starting with 0)
      *  @return The frame requested or NULL if not existing
      */
-    virtual const DcmIODTypes::Frame* getFrame(const size_t& frameNo);
+    virtual const DcmIODTypes::FrameBase* getFrame(const size_t& frameNo);
 
     /** Get the frame numbers that belong to a specific segment number
      *  @param  segmentNumber The segment to search frames for
@@ -320,8 +400,16 @@ public:
 
     /** Add segment to segmentation object
      *  @param  seg The segment that should be added
-     *  @param  segmentNumber The logical segment number that was assigned for
-     *          this segment. Contains 0 if adding failed.
+     *  @param  segmentNumber Depending on the type of segmentation, this
+     *          parameter is handled differently:
+     *          - For binary and fractional segmentations the segment number
+     *            is automatically assigned and will be returned in this
+     *            parameter. It is assigned from 0 onwards, i.e. the first
+     *            segment added will have segment number 1, the second 2, etc.
+     *          - For labelmap segmentations, the segment number is taken from
+     *            this parameter and can be >= 0. If the segment number is
+     *            already used, the method will overwrite an old segment with
+     *            this number.
      *  @return EC_Normal if adding was successful, error otherwise
      */
     virtual OFCondition addSegment(DcmSegment* seg, Uint16& segmentNumber);
@@ -334,20 +422,24 @@ public:
 
     /** Add frame to segmentation object
      *  @param  pixData Pixel data to be added. Length must be rows*columns bytes.
-     *          For binary segmentations (bit depth i.e.\ Bits
-     *          Allocated/Stored=1), each byte equal to 0 will be interpreted as
-     *          "not set", while every other value is interpreted as "set". For
-     *          fractional segmentations the full byte is copied as is.
+     *          - For binary segmentations (bit depth i.e.\ Bits
+     *            Allocated/Stored=1), each byte equal to 0 will be interpreted as
+     *            "not set", while every other value is interpreted as "set".
+     *          - For fractional segmentations the full byte is copied as is.
+     *          - For labelmap segmentations, the value of each byte is interpreted
+     *            as the segment number. In that case the segmentNumber parameters
+     *            is ignored.
      *  @param  segmentNumber The logical segment number (>=1) this frame refers to.
      *          The segment identified by the segmentNumber must already exist.
+     *          For labelmap segmentations, this parameter is ignored.
      *  @param  perFrameInformation The functional groups that identify this frame (i.e.
      *          which are planned to be not common for all other frames). The
      *          functional groups are copied, so ownership of each group stays
      *          with the caller no matter what the method returns.
      *  @return EC_Normal if adding was successful, error otherwise
      */
-    virtual OFCondition
-    addFrame(Uint8* pixData, const Uint16 segmentNumber, const OFVector<FGBase*>& perFrameInformation);
+    template <typename T>
+    OFCondition addFrame(T* pixData, const Uint16 segmentNumber, const OFVector<FGBase*>& perFrameInformation);
 
     /** Return reference to content content identification of this segmentation object
      *  @return Reference to content identification data
@@ -359,6 +451,16 @@ public:
      */
     virtual IODMultiframeDimensionModule& getDimensions();
 
+    /** Return reference to ICC Profile Module
+     *  @return Reference to ICC Profile Module
+     */
+    virtual IODICCProfileModule& getICCProfile();
+
+    /** Return reference to Palette Color Lookup Table module
+     *  @return Reference to Palette Color Lookup Table module
+     */
+    virtual IODPaletteColorLUTModule& getPaletteColorLUT();
+
     /** Set lossy compression flag of the segmentation object to "01". If one of the
      *  source images of this segmentation has undergone lossy compression then
      *  this function should be called.
@@ -429,11 +531,37 @@ public:
      */
     virtual OFCondition importFromSourceImage(const OFString& filename, const OFBool takeOverCharset = OFTrue);
 
+    /// Flags for loading segmentation objects. These flags can be used to
+    /// configure the loading of segmentation objects.
+    struct LoadingFlags
+    {
+        // Number of threads to use for reading per-frame functional groups
+        // (will also be applied to writing, if applicable later on)
+        Uint32 m_numThreads;
+
+        // Transfer syntax to use for reading/writing.
+        // transfer syntax used to read the data (auto detection if EXS_Unknown)
+        E_TransferSyntax m_readTransferSyntax;
+
+        /** Constructor to initialize the flags */
+        LoadingFlags() : m_numThreads(1), m_readTransferSyntax(EXS_Unknown) {}
+
+        /** Clear all flags to their default values */
+        void clear()
+        {
+            m_numThreads = 1;
+            m_readTransferSyntax = EXS_Unknown;
+        }
+    };
+
+
 protected:
+
     /** Protected default constructor. Library users should the factory create..()
      *  method in order to create an object from scratch
      */
-    DcmSegmentation();
+     template <typename ImagePixel>
+    DcmSegmentation(OFin_place_type_t(ImagePixel));
 
     /** Overwrites DcmIODImage::read()
      *  @param  dataset The dataset to read from
@@ -447,7 +575,8 @@ protected:
      */
     OFCondition readWithoutPixelData(DcmItem& dataset);
 
-    /** Writes the complete dataset without pixel data
+    /** Writes the complete dataset without pixel data, and write pixel data separately.
+     *  Version for 8 bit pixel data.
      *  @param  dataset The dataset to write to
      *  @param  pixData Buffer for pixel data to write to
      *  @param  pixDataLength Length of pixData buffer
@@ -455,6 +584,15 @@ protected:
      */
     OFCondition writeWithSeparatePixelData(DcmItem& dataset, Uint8*& pixData, size_t& pixDataLength);
 
+    /** Writes the complete dataset without pixel data, and write pixel data separately
+     *  Version for 16 bit pixel data.
+     *  @param  dataset The dataset to write to
+     *  @param  pixData Buffer for pixel data to write to
+     *  @param  pixDataLength Length of pixData buffer
+     *  @return EC_Normal if writing succeeded, error otherwise
+     */
+    OFCondition writeWithSeparatePixelData(DcmItem& dataset, Uint16*& pixData, size_t& pixDataLength);
+
     /** Create those data structures common for binary and fractional
      *  segmentations
      *  @param  segmentation The segmentation object created
@@ -462,19 +600,31 @@ protected:
      *  @param  columns The number of columns for the segmentation
      *  @param  equipmentInfo Equipment information
      *  @param  contentIdentification Content meta information
+     *  @param  bitsAllocated The number of bits allocated for the pixel data
+     *          8 for binary and fractional segmentations, 8 or 16 for labelmaps
      *  @return EC_Normal if creation was successful, error otherwise
      */
     static OFCondition createCommon(DcmSegmentation*& segmentation,
                                     const Uint16 rows,
                                     const Uint16 columns,
                                     const IODGeneralEquipmentModule::EquipmentInfo& equipmentInfo,
-                                    const ContentIdentificationMacro& contentIdentification);
+                                    const ContentIdentificationMacro& contentIdentification,
+                                    const Uint16 bitsAllocated);
 
-    /** Hide same function from IODImage since do not want the user to access
-     *  the image pixel module manually.
-     *  @return The Image Pixel Module
+    /** Creates segmentation object with pixel data matching required bit depths (as defined by Bits Allocated)
+     *  @param item The item to read Bits Allocated from (1, 8 or 16 bits permitted)
+     *  @param segmentation The segmentation object to create
+     *  @return EC_Normal if creation was successful, error otherwise
      */
-    virtual IODImagePixelModule<Uint8>& getImagePixel();
+    static OFCondition createRequiredBitDepth(DcmItem& item, DcmSegmentation*& segmentation);
+
+    /** Creates segmentation object with pixel data matching given bit depths
+     *  @param bitsAllocated The Bits Allocated value to use (1, 8 or 16 permitted)
+     *  @param segmentation The segmentation object to create
+     *  @return EC_Normal if creation was successful, error otherwise
+     */
+    static OFCondition createRequiredBitDepth(const Uint16 bitsAllocated, DcmSegmentation*& segmentation);
+
 
     /** Initialize IOD rules
      */
@@ -490,7 +640,8 @@ protected:
      *  @param  pixData The filled pixel data buffer returned by the method
      *  @return EC_Normal if writing was successful, error otherwise
      */
-    OFCondition writeFractionalFrames(Uint8* pixData);
+    template <typename T>
+    OFCondition writeByteBasedFrames(T* pixData);
 
     /** Write binary frames to given given pixel data buffer
      *  @param  pixData The filled pixel data buffer returned by the method
@@ -531,6 +682,15 @@ protected:
      */
     virtual OFCondition readFrames(DcmItem& dataset);
 
+    /** Read pixel data from given pixel data element
+     *  @param  pixelData The pixel data element to read from
+     *  @param  numFrames The number of frames expected in the pixel data element
+     *  @param  pixelsPerFrame The number of pixels per frame (rows*columns)
+     *  @param  bitsAlloc Bits Allocated value (1, 8 or 16)
+     *  @return EC_Normal if reading was successful, error otherwise
+     */
+    virtual OFCondition readPixelData(DcmElement* pixelData, const size_t numFrames, const size_t pixelsPerFrame, const Uint16 bitsAlloc);
+
     /** Get Image Pixel module attributes and perform some basic checking
      *  @param  dataset Item to read from, usually main dataset level
      *  @param  allocated Bits Allocated
@@ -560,9 +720,41 @@ protected:
      *          Pixel data is copied so it must be freed by the caller.
      *  @return EC_Normal if adding was successful, error otherwise
      */
-    virtual OFCondition addFrame(Uint8* pixData);
+    template <typename T>
+    OFCondition addFrame(T* pixData);
+
+    /** Determine color model. The color model is always MONOCHROME2, except for
+     *  labelmaps where PALETTE is permitted. This method checks whether the
+     *  we have a labelmap and if returns the correct string for setting Photometric
+     *  Interpretation based on desired color model setting (m_LabelmapColorModel).
+     *  If unknown color model is requested, MONOCHROME2 and a warning is printed.
+     *  @return The color model string for Photometric Interpretation attribute.
+     */
+    OFString determineColorModel();
+
+    /** Checks whether color model found in photometricInterpretation parameter is valid,
+     *  i.e. MONOCHROME2, or in case of labelmaps MONOCHROME2 or PALETTE.
+     *  Sets internal flag m_labelmapColorModel (for labelmaps) accordingly.
+     *  @param  photometricInterpretation The color model to check
+     *          (e.g. MONOCHROME2, PALETTE, etc.)
+     *  @return OFTrue if color model is valid, OFFalse otherwise
+     */
+    OFBool checkColorModel(const OFString& photometricInterpretation);
+
+    /** Sets the SOP Class UID based on the segmentation type,
+     *  i.e. whether it is a binary or fractional (Segmentation Storage SOP Class)
+     *  or a labelmap segmentation (Labelmap Segmentation Storage SOP Class).
+     *  The SOP Class UID is set to the following values:
+     *  If the segmentation type is unknown, the SOP Class UID is set to
+     *  Segmentation Storage SOP Class as well but a warning is printed.
+    */
+    void setSOPClassUIDBasedOnSegmentationType();
 
 private:
+
+    struct SetRowsAndCols;
+    struct SetImagePixelModuleVisitor;
+
     // Modules supported:
     //
     // Patient Module (through DcmIODImage)
@@ -575,6 +767,7 @@ private:
     // Enhanced General Equipment Module (through DcmIODImage)
     // General Image Module (through DcmIODImage)
     // Image Pixel Module (through DcmIODImage)
+    // Palette Color LUT Module (through this class)
     // Segmentation Image Module (through this class)
     // Multi-frame Functional Group Module
     // Multi-Frame Dimension Module
@@ -593,8 +786,21 @@ private:
     /// Multi-frame Dimension Module
     IODMultiframeDimensionModule m_DimensionModule;
 
+    /// Palette Color LUT Module
+    IODPaletteColorLUTModule m_PaletteColorLUTModule;
+
+    /// ICC Profile
+    IODICCProfileModule m_ICCProfileModule;
+
     /// Binary frame data
-    OFVector<DcmIODTypes::Frame*> m_Frames;
+    OFVector<DcmIODTypes::FrameBase*> m_Frames;
+
+    /// Denotes whether 16 bit pixel data is used
+    OFBool m_16BitPixelData;
+
+    /// Denotes in case of label maps the color model to be used
+    /// (only relevant for label maps, ignored for binary and fractional segmentations)
+    DcmSegTypes::E_SegmentationLabelmapColorModel m_LabelmapColorModel;
 
     /* Image level information */
 
@@ -615,12 +821,21 @@ private:
     /// Maximum Fractional Value: (US, 1, 1C) (required if fractional type is FRACTIONAL)
     DcmUnsignedShort m_MaximumFractionalValue;
 
-    /// Segment descriptions from Segment Sequence
-    OFVector<DcmSegment*> m_Segments;
+    /// Segment descriptions from Segment Sequence.
+    /// Maps Segment Number to Segment Description data.
+    /// For Labelmaps, the Segment Number is the label value, i.e. the pixel
+    /// value used in the pixel data to denote the segment.
+    OFMap<Uint16, DcmSegment*> m_Segments;
 
     /// Multi-frame Functional Groups high level interface
     FGInterface m_FGInterface;
 
+    /// Input transfer syntax; can be EXS_Unknown if object has been
+    /// created from scratch (and not from file or dataset). If the
+    /// segmentation has been loaded from a concatenation, the value
+    /// will be EXS_Unknown.
+    E_TransferSyntax m_inputXfer;
+
     // --------------- private helper functions -------------------
 
     /** Clear old data
@@ -631,19 +846,22 @@ private:
      *  @param  pixelData The Pixel Data element
      *  @param  rows Number of rows
      *  @param  cols Number of columns
+     *  @param  bytesPerPixel Bytes per pixel (1 for 1 or 8 bit data, or 2 for 16 bit data)
      *  @param  numberOfFrames Number of frames
      *  @result OFTrue if length is valid, OFFalse otherwise
      */
     OFBool
-    checkPixDataLength(DcmElement* pixelData, const Uint16 rows, const Uint16 cols, const Uint32& numberOfFrames);
+    checkPixDataLength(DcmElement* pixelData, const Uint16 rows, const Uint16 cols, const Uint16 bytesPerPixel, const Uint32& numberOfFrames);
 
     /** Loads file
      *  @param  dcmff The file format to load into
      *  @param  filename The filename of the file to load
      *  @param  dset Pointer to dataset after loading
+     *  @param  xfer Transfer syntax to use for reading
+     *    (if EXS_Unknown,the default, auto detection is used)
      *  @return EC_Normal if loading was successful, error otherwise
      */
-    static OFCondition loadFile(DcmFileFormat& dcmff, const OFString& filename, DcmDataset*& dset);
+    static OFCondition loadFile(DcmFileFormat& dcmff, const OFString& filename, DcmDataset*& dset, const E_TransferSyntax xfer);
 
     /** Computes the number of total bytes required for the frame data of this
      *  segmentation object. Takes into account dimensions and number of frames,
@@ -651,6 +869,7 @@ private:
      *  size_t type is not able to hold the result of intermediate computations.
      *  @param  rows Number of rows of a frame
      *  @param  cols Number of cols of a frame
+     *  @param  bytesPerPixel Bytes per pixel (use 1 for 1 or 8 bit data, or 2 for 16 bit data)
      *  @param  numberOfFrames The number of frames of the object
      *  @param  bytesRequired Will hold the result of the computation,
      *          if successful. Does not any padding into account.
@@ -658,7 +877,7 @@ private:
      *          otherwise.
      */
     OFCondition
-    getTotalBytesRequired(const Uint16& rows, const Uint16& cols, const Uint32& numberOfFrames, size_t& bytesRequired);
+    getTotalBytesRequired(const Uint16& rows, const Uint16& cols, const Uint16& bytesPerPixel, const Uint32& numberOfFrames, size_t& bytesRequired);
 
     /** Read Fractional Type of segmentation.
      *  @param  item The item to read from
@@ -682,4 +901,220 @@ private:
     static OFCondition decompress(DcmDataset& dset);
 };
 
+
+template <typename T>
+OFCondition DcmSegmentation::addFrame(T* pixData)
+{
+    if (m_Frames.size() >= DCM_SEG_MAX_FRAMES)
+        return SG_EC_MaxFramesReached;
+
+    OFCondition result;
+    Uint16 rows = 0;
+    Uint16 cols = 0;
+    if (getImagePixel().getRows(rows).good() && getImagePixel().getColumns(cols).good())
+    {
+        DcmIODTypes::Frame<T>* frame = NULL;
+
+        // Diagnostic push/pop for Visual Studio that disables
+        // warning on constant expressions, in this case the
+        // if statement if (sizeof(T) != 1) which is known for
+        // each template instantiation at compile time. One can
+        // use constexpr if available to avoid this warning but this
+        // is not available in all cases
+        #include DCMTK_DIAGNOSTIC_PUSH
+        #include DCMTK_DIAGNOSTIC_IGNORE_VISUAL_STUDIO_CONSTANT_EXPRESSION_WARNING
+        switch (m_SegmentationType)
+        {
+            case DcmSegTypes::ST_BINARY:
+            {
+                if (sizeof(T) != 1) // 8 bit pixel data
+                {
+                    DCMSEG_ERROR("Cannot add frame: 16 bit pixel data expected but 8 bit pixel data provided");
+                    result = IOD_EC_InvalidPixelData;
+                    break;
+                }
+                // Pack the binary frame
+                frame = DcmSegUtils::packBinaryFrame<T>(pixData, rows, cols);
+                if (!frame)
+                    result = IOD_EC_CannotInsertFrame;
+                break;
+            }
+            case DcmSegTypes::ST_FRACTIONAL:
+            case DcmSegTypes::ST_LABELMAP:
+            {
+                frame = new DcmIODTypes::Frame<T>(rows * cols);
+
+                if (frame)
+                {
+                    if (frame->m_pixData)
+                    {
+                        memcpy(frame->m_pixData, pixData, frame->getLengthInBytes());
+                    }
+                    else
+                    {
+                        delete frame;
+                        result = EC_MemoryExhausted;
+                    }
+                }
+                else
+                    result = EC_MemoryExhausted;
+                break;
+            }
+            case DcmSegTypes::ST_UNKNOWN:
+            default:
+                result = SG_EC_UnknownSegmentationType;
+                break;
+        }
+        // re-enable diagnostic warnings
+        #include DCMTK_DIAGNOSTIC_POP
+        if (result.good())
+        {
+            m_Frames.push_back(frame);
+        }
+    }
+    else
+    {
+        DCMSEG_ERROR("Cannot add frame since rows and/or columns are unknown");
+        result = IOD_EC_CannotInsertFrame;
+    }
+    return result;
+}
+
+
+/** Add frame to segmentation object
+ *  @param  pixData Pixel data to be added. Length must be rows*columns bytes.
+ *          - For binary segmentations (bit depth i.e.\ Bits
+ *            Allocated/Stored=1), each byte equal to 0 will be interpreted as
+ *            "not set", while every other value is interpreted as "set".
+ *          - For fractional segmentations the full byte is copied as is.
+ *          - For labelmap segmentations, the value of each byte is interpreted
+ *            as the segment number. In that case the segmentNumber parameters
+ *            is ignored.
+ *  @param  segmentNumber The logical segment number (>=1) this frame refers to.
+ *          The segment identified by the segmentNumber must already exist.
+ *          For labelmap segmentations, this parameter is ignored.
+ *  @param  perFrameInformation The functional groups that identify this frame (i.e.
+ *          which are planned to be not common for all other frames). The
+ *          functional groups are copied, so ownership of each group stays
+ *          with the caller no matter what the method returns.
+ *  @return EC_Normal if adding was successful, error otherwise
+ */
+template <typename T>
+OFCondition
+DcmSegmentation::addFrame(T* pixData, const Uint16 segmentNumber, const OFVector<FGBase*>& perFrameInformation)
+{
+    if (m_Frames.size() >= DCM_SEG_MAX_FRAMES)
+        return SG_EC_MaxFramesReached;
+
+    if (m_16BitPixelData && (sizeof(T) != 2))
+    {
+        DCMSEG_ERROR("Cannot add frame: 16 bit pixel data expected but 8 bit pixel data provided");
+        return IOD_EC_InvalidPixelData;
+    }
+    else if (!m_16BitPixelData && (sizeof(T) == 2))
+    {
+        DCMSEG_ERROR("Cannot add frame: 8 bit pixel data expected but 16 bit pixel data provided");
+        return IOD_EC_InvalidPixelData;
+    }
+
+    Uint32 frameNo = OFstatic_cast(Uint32, m_Frames.size()); // will be the index of the frame (counted from 0)
+    OFCondition result;
+
+    // Check input parameters
+    if (pixData == NULL)
+    {
+        DCMSEG_ERROR("No pixel data provided or zero length");
+        result = EC_IllegalParameter;
+    }
+    if (segmentNumber == 0)
+    {
+        if (m_SegmentationType != DcmSegTypes::ST_LABELMAP)
+        {
+            DCMSEG_ERROR("Cannot add frame: Segment number 0 is not permitted for segmentation type "
+                         << DcmSegTypes::segtype2OFString(m_SegmentationType));
+            result = SG_EC_NoSuchSegment;
+        }
+        // we ignore the segment number for label maps
+    }
+    // If this is not a labelmap, check if segment the frame refers to actually exists
+    else if  ((m_SegmentationType != DcmSegTypes::ST_LABELMAP) && (getSegment(segmentNumber) == NULL) )
+    {
+        DCMSEG_ERROR("Cannot add frame: Segment with given number " << segmentNumber << " does not exist");
+        result = SG_EC_NoSuchSegment;
+    }
+    if (result.bad())
+        return result;
+
+    OFVector<FGBase*>::const_iterator it = perFrameInformation.begin();
+    while (it != perFrameInformation.end())
+    {
+        // Labelmap is not permitted to have Segmentation Functional Group,
+        // and for other segmentation types we create it automatically, ignore if found
+        if ((*it)->getType() == DcmFGTypes::EFG_SEGMENTATION)
+        {
+            if (m_SegmentationType == DcmSegTypes::ST_LABELMAP)
+            {
+                DCMSEG_WARN("Ignoring provided Segmentation Functional Group, not permitted for labelmap segmentation");
+                it++;
+                continue;
+            }
+            else
+            {
+                DCMSEG_WARN("Ignoring provided Segmentation Functional Group, will be created automatically");
+                it++;
+                continue;
+            }
+        }
+        result = (*it)->check();
+        if (result.bad())
+        {
+            DCMSEG_ERROR("Could not add new frame since functional group of type: "
+                         << (*it)->getType() << " is invalid: " << result.text());
+            break;
+        }
+        result = m_FGInterface.addPerFrame(frameNo, *(*it));
+        if (result.bad())
+        {
+            DCMSEG_ERROR("Could not add new frame since functional group of type " << (*it)->getType() << ": "
+                                                                                   << result.text());
+            break;
+        }
+        it++;
+    }
+
+    // Now also add Segmentation Functional Group
+    if (result.good() && (m_SegmentationType != DcmSegTypes::ST_LABELMAP))
+    {
+        FGSegmentation seg;
+        result = seg.setReferencedSegmentNumber(segmentNumber);
+        if (result.good())
+        {
+            result = m_FGInterface.addPerFrame(frameNo, seg);
+        }
+        else
+        {
+            DCMSEG_ERROR("Could not add new frame, invalid segment number " << segmentNumber << ": " << result.text());
+        }
+    }
+
+    // Insert pixel data
+    if (result.good())
+    {
+        result = addFrame<T>(pixData);
+    }
+
+    // Cleanup any per-frame groups that might have been inserted and return
+    if (result.bad())
+    {
+        for (OFVector<FGBase*>::const_iterator it2 = perFrameInformation.begin(); it2 != perFrameInformation.end();
+             it2++)
+        {
+            m_FGInterface.deletePerFrame(frameNo, (*it2)->getType());
+        }
+    }
+
+    return result;
+}
+
+
 #endif // SEGDOC_H
index baf3b816a068153e44eac376bfc00cb9abf50e29..f69f1c6da1fe777bcb4969e0bff72a92f7e8268b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 
 #include "dcmtk/dcmdata/dcvrus.h"
 #include "dcmtk/dcmiod/iodmacro.h"
-#include "dcmtk/dcmseg/segdoc.h"
 #include "dcmtk/dcmseg/segtypes.h"
 #include "dcmtk/dcmdata/dcvrui.h"
 #include "dcmtk/dcmdata/dcvrlo.h"
 #include "dcmtk/dcmdata/dcvrut.h"
 
-/** Class representing a segment from the Segment Identification Sequence,
- *  as used within the Segmentation Image Module. It includes the Segment
- *  Description Macro.
- */
+class DcmSegmentation;
 
+/** Class that represents a Segment inside a Segmentation object.
+ *  It mostly represents data as found in an item of the Segment Identification
+ *  Sequence (Segmentation Image Module).
+ */
 class DCMTK_DCMSEG_EXPORT DcmSegment
 {
 
@@ -76,6 +76,25 @@ public:
                               const DcmSegTypes::E_SegmentAlgoType algoType,
                               const OFString& algoName = "");
 
+    /** Make a clone of this segment.
+     *  Note that the reference to DcmSegmentation is copied, if not provided in the parameter.
+     *  @param seg Pointer to the DcmSegmentation object to associate with the cloned segment,
+     *         copied from the original segment if not provided
+     *  @return Pointer to the cloned segment if successful, OFnullptr otherwise
+     */
+    DcmSegment* clone(DcmSegmentation* seg = NULL);
+
+    /** Assignment operator, performs deep copy
+     *  @param  rhs The right-hand side segment to assign from
+     *  @return Reference to this segment
+     */
+    DcmSegment& operator=(const DcmSegment& rhs);
+
+    /** Copy constructor
+     *  @param  rhs The right-hand side segment to copy from
+     */
+    DcmSegment(const DcmSegment& rhs);
+
     // ---------------- writing --------------------
 
     /** Write segment to given item which is usually contained within
@@ -259,6 +278,16 @@ public:
      */
     virtual OFCondition setTrackingUID(const OFString& value, const OFBool checkValue = OFTrue);
 
+    /** THIS IS ONLY FOR INTERNAL USE. DO NOT USE this as a regular API user.
+     *  Get Segment Number as read from the Segment Sequence for this segment.
+     *  It may be different from the Segment Number as returned by getSegmentNumber(),
+     *  i.e. do not rely on this method for anything.
+     *  @return EC_Normal if successful, an error code otherwise
+     */
+    virtual Uint16 getSegmentNumberRead();
+
+    OFshared_ptr<IODRules> getIODRules();
+
     /// The utility class must access the protected default constructor
     friend class DcmIODUtil;
 
@@ -279,18 +308,16 @@ protected:
     void referenceSegmentationDoc(DcmSegmentation* doc);
 
 private:
-    /** Private undefined copy constructor
-     */
-    DcmSegment(const DcmSegment&);
-
-    /** Private undefined assignment operator
-     *  @return Reference to "this" class
-     */
-    DcmSegment& operator=(const DcmSegment&);
 
     /// The segmentation document where this segment is located in
     DcmSegmentation* m_SegmentationDoc;
 
+    /// The segment number as read from the Segment Number attribute.
+    /// This attribute only holds the number read from the file/item,
+    /// and will be updated only during a write process. It is not meant
+    /// to be used by the API user at all but only for internal purposes.
+    DcmUnsignedShort m_SegmentNumber;
+
     /// Segment Description Macro
     SegmentDescriptionMacro m_SegmentDescription;
 
@@ -316,7 +343,7 @@ private:
     DcmUniqueIdentifier m_TrackingUID;
 
     /// Rules for data elements within this IOD
-    IODRules m_Rules;
+    OFshared_ptr<IODRules> m_Rules;
 };
 
 #endif // SEGMENT_H
index a0a0dec242a8f13577bcd4e8d7877564c1778894..9e06788f730d0750e92627832341c2e1a7810340 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -67,7 +67,7 @@ const Uint32 DCM_SEG_MAX_FRAMES = 2147483647; // 2^31-1
  *  These error codes can be used in addition to the general purpose
  *  codes defined in module dcmdata.
  */
-//@{
+///@{
 
 /// error: specified functional group is already existing
 extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_MaxSegmentsReached;
@@ -81,6 +81,26 @@ extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_InvalidValue;
 extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_NotEnoughData;
 /// error: too many frames
 extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_MaxFramesReached;
+/// error: invalid bit depth
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_InvalidBitDepth;
+/// error: frames are not parallel
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_FramesNotParallel;
+/// error: no segmentation SOP class (Segmentation or Label Map Segmentation SOP Class)
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_NoSegmentationBasedSOPClass;
+/// error: segmentation-based object does not require conversion
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_NoConversionRequired;
+/// error: cannot convert fractional to labelmap segmentations
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_CannotConvertFractionalToLabelmap;
+/// error: segmentation-based object is already a label map
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_AlreadyLabelMap;
+/// error: binary segmentation contains overlapping segments
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_OverlappingSegments;
+/// error: cannot convert to PALETTE color model since not all segments contain Recommended Display CIELab Value Macro
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_CannotConvertMissingCIELab;
+/// error: missing Plane Position (Patient) Functional Group
+extern DCMTK_DCMSEG_EXPORT const OFConditionConst SG_EC_MissingPlanePositionPatient;
+
+///@}
 
 /** General purpose class hiding global functions, constants and types in the
  *  segmentation context from the global namespace.
@@ -100,7 +120,10 @@ public:
         ST_BINARY,
         /// Fractional segmentation where fraction specifies how much of voxel
         /// is occupied by the segment
-        ST_FRACTIONAL
+        ST_FRACTIONAL,
+        /// Labelmap segmentation where each segment is assigned a unique
+        // integer value in the pixel data (EXPERIMENTAL: based on Supplement 243 public comment 2014-01-08)
+        ST_LABELMAP
     };
 
     /** Segment Algorithm Type
@@ -129,6 +152,18 @@ public:
         SFT_OCCUPANCY
     };
 
+    /** Labelmap Segmentation desired color model
+     */
+    enum E_SegmentationLabelmapColorModel
+    {
+        /// Unknown (e.g.\ not initialized)
+        SLCM_UNKNOWN,
+        /// Monochrome 1 Bit
+        SLCM_MONOCHROME2,
+        /// Palette Color
+        SLCM_PALETTE
+    };
+
     // -- helper functions --
 
     /** Return string representation of algorithm type
@@ -163,6 +198,20 @@ public:
      *  @return The fractional type as enum value
      */
     static DcmSegTypes::E_SegmentationFractionalType OFString2FractionalType(const OFString& value);
+
+    /** Returns string representation from labelmap color enum type
+     *  @param  value The labelmap color model as enum value
+     *  @param  fallbackValue The value to use if the enum value is unknown or invalid (not used if empty)
+     *  @return The labelmap color model as a string
+     */
+    static OFString labelmapColorModel2OFString(const DcmSegTypes::E_SegmentationLabelmapColorModel value, const OFString& fallbackValue="");
+
+    /** Return enum representation of photometric interpretation type string as found in
+     *  segmentation objects.
+     *  @param  value The photometric interpretation type as a string
+     *  @return The photometric interpretation type as enum value
+     */
+    static DcmSegTypes::E_SegmentationLabelmapColorModel OFString2LabelmapColorModel(const OFString& value);
 };
 
 /** Class representing the Segmented Property Type Code and Segmented
@@ -183,6 +232,24 @@ public:
      */
     virtual ~SegmentedPropertyTypeCodeItem();
 
+    /** Clone method, creates a new instance of this class and performs
+     *  a deep copy of all data.
+     *  @return Pointer to newly created SegmentedPropertyTypeCodeItem object. The
+     *          caller is responsible for deleting the object after use.
+     */
+    virtual SegmentedPropertyTypeCodeItem* clone();
+
+    /** Assignment operator, performs deep copy
+     *  @param  rhs The right-hand side SegmentedPropertyTypeCodeItem to assign from
+     *  @return Reference to this SegmentedPropertyTypeCodeItem
+     */
+    SegmentedPropertyTypeCodeItem& operator=(const SegmentedPropertyTypeCodeItem& rhs);
+
+    /** Copy constructor
+     *  @param  rhs The right-hand side SegmentedPropertyTypeCodeItem to copy from
+     */
+    SegmentedPropertyTypeCodeItem(const SegmentedPropertyTypeCodeItem& rhs);
+
     /** Clear all data
      */
     virtual void clearData();
@@ -238,6 +305,19 @@ public:
      */
     virtual ~SegmentDescriptionMacro();
 
+    /** Clone method, creates a new instance of this class and performs
+     *  a deep copy of all data.
+     *  @return Pointer to newly created SegmentDescriptionMacro object. The
+     *          caller is responsible for deleting the object after use.
+     */
+    virtual SegmentDescriptionMacro* clone();
+
+    /** Assignment operator, performs deep copy
+     *  @param  rhs The right-hand side SegmentDescriptionMacro to assign from
+     *  @return Reference to this SegmentDescriptionMacro
+     */
+    SegmentDescriptionMacro& operator=(const SegmentDescriptionMacro& rhs);
+
     /** Clear all data
      */
     virtual void clearData();
index a8b1a91d9c379dda8cc67b78369116e272995c87..dc0471c67aa58f0d8493d07d854c1c0dd9720e49 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -26,6 +26,7 @@
 
 #include "dcmtk/dcmseg/segdef.h"
 #include "dcmtk/dcmseg/segtypes.h"
+#include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/ofstd/oftypes.h"
 #include "dcmtk/ofstd/ofvector.h"
 
@@ -42,7 +43,8 @@ public:
      *  @param  columns The number of columns in the pixel data
      *  @return The frame data if successful, NULL if an error occurs
      */
-    static DcmIODTypes::Frame* packBinaryFrame(const Uint8* pixelData, const Uint16 rows, const Uint16 columns);
+    template <typename T>
+    static DcmIODTypes::Frame<T>* packBinaryFrame(const T* pixelData, const Uint16 rows, const Uint16 columns);
 
     /** Concatenate given frames into a single bit array
      *  @param  frames The frames to concatenate. Each frame is expected to be in packed format (1 bit per pixel),
@@ -54,7 +56,7 @@ public:
      *  @param  pixDataLength The length of the pixData buffer in bytes
      *  @return EC_Normal if successful, an error code otherwise
      */
-    static OFCondition concatBinaryFrames(const OFVector<DcmIODTypes::Frame*>& frames, const Uint16 rows, const Uint16 cols, Uint8* pixData, const size_t pixDataLength);
+    static OFCondition concatBinaryFrames(const OFVector<DcmIODTypes::FrameBase*>& frames, const Uint16 rows, const Uint16 cols, Uint8* pixData, const size_t pixDataLength);
 
     /** Unpacks a binary segmentation frame into a "sparse" pixel data frame where
      *  every resulting byte represents a single bit of the frame being either
@@ -64,7 +66,8 @@ public:
      *  @param  cols The cols of the frame
      *  @return The segmentation frame in unpacked format. NULL in case of error.
      */
-    static DcmIODTypes::Frame* unpackBinaryFrame(const DcmIODTypes::Frame* frame, Uint16 rows, Uint16 cols);
+    static DcmIODTypes::Frame<Uint8>*
+    unpackBinaryFrame(const DcmIODTypes::Frame<Uint8>* frame, Uint16 rows, Uint16 cols);
 
 
     /** Dumps a byte as binary number to a string. Only useful for
@@ -83,6 +86,82 @@ public:
      *  otherwise bytes are enumerated
      */
     static void debugDumpBin(Uint8* buffer, size_t length, const OFString& what, const OFBool raw);
+
 };
 
+/** Pack the given segmentation pixel data, provided "unpacked", into
+ *  the packed format expected by DICOM. This is the default version which prints an error
+ *  and returns NULL.
+ *  @return Returns NULL
+ */
+template<typename T>
+DcmIODTypes::Frame<T>*
+DcmSegUtils::packBinaryFrame(const T*, const Uint16, const Uint16)
+{
+    // Return error since this function is not specialized for T
+    DCMSEG_ERROR("packBinaryFrame() can only be used for Uint8 data but you provided something else");
+    return NULL;
+}
+
+/** Pack the given segmentation pixel data, provided "unpacked", into
+ *  the packed format expected by DICOM. This is the 8 bit version which
+ *  is the only version actually used for segmentation objects.
+ *  @param  pixelData Pixel data in unpacked format, i.e on byte per pixel, either 0 (not set) or non-0 (set)
+ *  @param  rows Number of rows in the pixel data
+ *  @param  columns The number of columns in the pixel data
+ *  @return Frame data if successful, NULL if an error occurs
+ */
+template<>
+inline DcmIODTypes::Frame<Uint8>*
+DcmSegUtils::packBinaryFrame(const Uint8* pixelData, const Uint16 rows, const Uint16 columns)
+{
+    // Sanity checking
+    const size_t totalBits = OFstatic_cast(size_t, rows) * columns;
+    if (totalBits == 0)
+    {
+        DCMSEG_ERROR("Unable to pack binary segmentation frame: Rows or Columns is 0");
+        return NULL;
+    }
+    if (!pixelData)
+    {
+        DCMSEG_ERROR("Unable to pack binary segmentation frame: No pixel data provided");
+        return NULL;
+    }
+
+    // Calculate total number of bytes required
+    size_t totalBytes = (totalBits + 7) / 8; // +7 to round up to the nearest byte
+
+    // Allocate memory for the packed bit array
+    Uint8* packedData = new Uint8[totalBytes];
+    if (packedData == NULL)
+    {
+        DCMSEG_ERROR("Cannot allocate memory for packed binary frame");
+        return NULL;
+    }
+    memset(packedData, 0, totalBytes); // Initialize to 0
+
+    // Pack the bits
+    for (Uint32 i = 0; i < totalBits; ++i) {
+        if (pixelData[i] != 0) {
+            Uint32 byteIndex = i / 8;
+            Uint32 bitIndex = i % 8;
+            DCMSEG_TRACE("bitIndex: " << bitIndex << ", byteIndex: " << byteIndex << ", packedData[byteIndex]: " << DcmSegUtils::debugByte2Bin(packedData[byteIndex]));
+            packedData[byteIndex] |= (1 << bitIndex); // Fill from right to left
+        }
+    }
+
+    // Create and return the frame
+    DcmIODTypes::Frame<Uint8>* frame = new DcmIODTypes::Frame<Uint8>();
+    if (frame == NULL)
+    {
+        DCMSEG_ERROR("Cannot allocate memory for packed binary frame");
+        delete[] packedData;
+        return NULL;
+    }
+    frame->m_pixData = packedData;
+    frame->m_numPixels = totalBytes; // for binary frames, numPixels must be set to the number of bytes used
+    return frame; // Return the packed frame
+}
+
+
 #endif // SEGUTILS_H
index f11bfae3e175ed78b253386af5c6210b3d51f5c5..faccbed5cfadfc4ec7f317cde1f828ef3bbd8bc2 100644 (file)
@@ -1,5 +1,6 @@
 # create library from source files
 DCMTK_ADD_LIBRARY(dcmseg
+  overlaputil.cc
   segdoc.cc
   segment.cc
   segtypes.cc
index 1bbbdf6eb4a7183c60317d3ab14a841fd97e0639..83d4caf1cbc45099de840cfb66099ff66a7ae4e1 100644 (file)
-segdoc.o: segdoc.cc ../../config/include/dcmtk/config/osconfig.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+overlaputil.o: overlaputil.cc ../include/dcmtk/dcmseg/overlaputil.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../config/include/dcmtk/config/osconfig.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
- ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
- ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/ofstream.h \
- ../../ofstd/include/dcmtk/ofstd/ofstd.h \
- ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
  ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../dcmfg/include/dcmtk/dcmfg/framesorter.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmath.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fg.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../include/dcmtk/dcmseg/segdoc.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/stralias.def \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h \
+ ../../ofstd/include/dcmtk/ofstd/oftimer.h
+segdoc.o: segdoc.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
@@ -41,6 +152,7 @@ segdoc.o: segdoc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
  ../../oflog/include/dcmtk/oflog/layout.h \
  ../../oflog/include/dcmtk/oflog/streams.h \
@@ -52,38 +164,52 @@ segdoc.o: segdoc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
- ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../dcmfg/include/dcmtk/dcmfg/fgderimg.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
- ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
- ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
- ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
  ../include/dcmtk/dcmseg/segdoc.h \
@@ -110,33 +236,39 @@ segdoc.o: segdoc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
  ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
  ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
- ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segtypes.h \
- ../include/dcmtk/dcmseg/segment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
  ../include/dcmtk/dcmseg/segutils.h
 segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
- ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
- ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
  ../../ofstd/include/dcmtk/ofstd/ofstd.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../ofstd/include/dcmtk/ofstd/oflimits.h \
  ../../ofstd/include/dcmtk/ofstd/oferror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
@@ -164,7 +296,6 @@ segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
@@ -173,8 +304,6 @@ segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
- ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
- ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
@@ -183,6 +312,7 @@ segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -195,16 +325,16 @@ segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmfg/include/dcmtk/dcmfg/fg.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
  ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
@@ -225,13 +355,16 @@ segment.o: segment.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
  ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
  ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
- ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmseg/segment.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h
 segtypes.o: segtypes.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../ofstd/include/dcmtk/ofstd/ofcond.h \
@@ -297,6 +430,7 @@ segtypes.o: segtypes.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
@@ -354,11 +488,13 @@ segutils.o: segutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
@@ -368,7 +504,6 @@ segutils.o: segutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
index 9728e81a31df04075f97ad481a49ef99be61a388..271532388b3ef0db71ddafa30a134d6f44ff47ce 100644 (file)
@@ -22,7 +22,7 @@ LOCALINCLUDES = -I$(ofstddir)/include -I$(oflogdir)/include \
        -I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include
 LOCALDEFS =
 
-objs = segdoc.o segment.o segtypes.o segutils.o
+objs = overlaputil.o segdoc.o segment.o segtypes.o segutils.o
 
 library = libdcmseg.$(LIBEXT)
 
diff --git a/dcmseg/libsrc/overlaputil.cc b/dcmseg/libsrc/overlaputil.cc
new file mode 100644 (file)
index 0000000..7747c72
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ *
+ *  Copyright (C) 2023-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmqi
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Interface of class OverlapUtil
+ *
+ */
+
+#include "dcmtk/dcmseg/overlaputil.h"
+#include "dcmtk/dcmfg/framesorter.h"
+#include "dcmtk/dcmdata/dcerror.h"
+#include "dcmtk/dcmfg/fginterface.h"
+#include "dcmtk/dcmfg/fgpixmsr.h"
+#include "dcmtk/dcmfg/fgplanor.h"
+#include "dcmtk/dcmfg/fgseg.h"
+#include "dcmtk/dcmfg/fgtypes.h"
+#include "dcmtk/dcmiod/iodtypes.h"
+#include "dcmtk/dcmseg/segdoc.h"
+#include "dcmtk/dcmseg/segtypes.h"
+#include "dcmtk/dcmseg/segutils.h"
+#include "dcmtk/ofstd/ofcond.h"
+#include "dcmtk/ofstd/ofstream.h"
+#include "dcmtk/ofstd/oftimer.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+OverlapUtil::OverlapUtil()
+    : m_imageOrientation()
+    , m_framePositions()
+    , m_framesForSegment()
+    , m_logicalFramePositions()
+    , m_segmentsByPosition()
+    , m_segmentOverlapMatrix(0)
+    , m_nonOverlappingSegments()
+    , m_seg()
+{
+}
+
+OverlapUtil::~OverlapUtil()
+{
+    // nothing to do
+}
+
+void OverlapUtil::setSegmentationObject(DcmSegmentation* seg)
+{
+    m_seg = seg;
+    clear();
+}
+
+void OverlapUtil::clear()
+{
+    m_imageOrientation.clear();
+    m_framePositions.clear();
+    m_framesForSegment.clear();
+    m_logicalFramePositions.clear();
+    m_segmentsByPosition.clear();
+    m_segmentOverlapMatrix.clear();
+    m_nonOverlappingSegments.clear();
+}
+
+OFCondition OverlapUtil::getFramesByPosition(DistinctFramePositions& result)
+{
+    OFCondition cond;
+    if (!m_seg)
+    {
+        DCMSEG_ERROR("getFramesByPosition(): No segmentation object set");
+        return EC_IllegalCall;
+    }
+    if (m_logicalFramePositions.empty())
+    {
+        cond = groupFramesByPosition();
+    }
+    if (cond.good())
+    {
+        result = m_logicalFramePositions;
+    }
+    return cond;
+}
+
+OFCondition OverlapUtil::getFramesForSegment(const Uint32 segmentNumber, OFVector<Uint32>& frames)
+{
+    if (!m_seg)
+    {
+        DCMSEG_ERROR("getFramesForSegment(): No segmentation object set");
+        return EC_IllegalCall;
+    }
+    if ((segmentNumber == 0) || (segmentNumber > m_seg->getNumberOfSegments()))
+    {
+        DCMSEG_ERROR("getFramesForSegment(): Segment number " << segmentNumber << " is out of range");
+        return EC_IllegalParameter;
+    }
+    if (m_framesForSegment.empty())
+    {
+        FGInterface& fg  = m_seg->getFunctionalGroups();
+        size_t tempNum = m_seg->getNumberOfFrames();
+        if (tempNum > 4294967295)
+        {
+            DCMSEG_ERROR("getFramesForSegment(): Number of frames " << tempNum << " exceeds maximum number of possible frames (2^32-1)");
+            return EC_IllegalParameter;
+        }
+        Uint32 numFrames = static_cast<Uint32>(m_seg->getNumberOfFrames());
+        m_framesForSegment.clear();
+        m_framesForSegment.resize(m_seg->getNumberOfSegments());
+        // Get Segmentation FG for each frame and remember the segment number for each frame
+        // in the vector m_segmentsForFrame
+        for (Uint32 f = 0; f < numFrames; f++)
+        {
+            FGBase* group         = NULL;
+            FGSegmentation* segFG = NULL;
+            group                 = fg.get(f, DcmFGTypes::EFG_SEGMENTATION);
+            segFG                 = OFstatic_cast(FGSegmentation*, group);
+            if (segFG)
+            {
+                Uint16 segNum    = 0;
+                OFCondition cond = segFG->getReferencedSegmentNumber(segNum);
+                if (cond.good() && segNum > 0)
+                {
+                    m_framesForSegment[segNum - 1].push_back(f); // physical frame number for segment
+                }
+                else if (segNum == 0)
+                {
+                    DCMSEG_WARN("getFramesForSegment(): Referenced Segment Number is 0 (not permitted) for frame #"
+                                << f << ", ignoring");
+                    return EC_InvalidValue;
+                }
+                else
+                {
+                    DCMSEG_ERROR(
+                        "getFramesForSegment(): Referenced Segment Number not found (not permitted) for frame #"
+                        << f << ", cannot add segment");
+                    return EC_TagNotFound;
+                }
+            }
+        }
+    }
+    frames = m_framesForSegment[segmentNumber - 1];
+    return EC_Normal;
+}
+
+OFCondition OverlapUtil::ensureFramesAreParallel()
+{
+    FGInterface& fg = m_seg->getFunctionalGroups();
+    OFCondition cond;
+    OFBool perFrame                = OFFalse;
+    FGPlaneOrientationPatient* pop = NULL;
+    // Ensure that Image Orientation Patient is shared, i.e. we have parallel frames
+    m_imageOrientation.clear();
+    m_imageOrientation.resize(6);
+    FGBase* group = fg.get(0, DcmFGTypes::EFG_PLANEORIENTPATIENT, perFrame);
+    pop = OFstatic_cast(FGPlaneOrientationPatient*, group);
+    if (pop)
+    {
+        if (perFrame == OFFalse)
+        {
+            DCMSEG_DEBUG("ensureFramesAreParallel(): Image Orientation Patient is shared, frames are parallel");
+            m_imageOrientation.resize(6);
+            cond = pop->getImageOrientationPatient(m_imageOrientation[0],
+                                                   m_imageOrientation[1],
+                                                   m_imageOrientation[2],
+                                                   m_imageOrientation[3],
+                                                   m_imageOrientation[4],
+                                                   m_imageOrientation[5]);
+            DCMSEG_DEBUG("Image Orientation Patient set to : " << m_imageOrientation[0] << ", " << m_imageOrientation[1]
+                      << ", " << m_imageOrientation[2] << ", " << m_imageOrientation[3] << ", " << m_imageOrientation[4]
+                      << ", " << m_imageOrientation[5]);
+        }
+        else
+        {
+            DCMSEG_ERROR(
+                "ensureFramesAreParallel(): Image Orientation Patient is per-frame, frames are probably not parallel");
+            return SG_EC_FramesNotParallel;
+        }
+    }
+    else
+    {
+        DCMSEG_ERROR(
+            "ensureFramesAreParallel(): Plane Orientation (Patient) FG not found, cannot check for parallel frames");
+        return EC_TagNotFound;
+    }
+    return cond;
+}
+
+OFCondition OverlapUtil::groupFramesByPosition()
+{
+    if (!m_framePositions.empty())
+    {
+        // Already computed
+        return EC_Normal;
+    }
+
+    OFCondition cond = ensureFramesAreParallel();
+    if (cond.bad())
+    {
+        return cond;
+    }
+
+    OFTimer tm;
+
+    // Group all frames by position into m_logicalFramePositions.
+    // After that, all frames at the same position will be in the same vector
+    // assigned to the same key (the frame's coordinates) in the map.
+    // Group all frames by position into m_logicalFramePositions.
+    FrameSorterIPP sorter;
+    sorter.setSorterInput(&(m_seg->getFunctionalGroups()));
+    FrameSorterIPP::Results results;
+    sorter.sort(results);
+    if (results.errorCode.bad())
+    {
+        DCMSEG_ERROR("groupFramesByPosition(): Cannot sort frames by position: " << results.errorCode.text());
+        return results.errorCode;
+    }
+    // Copy results from frame sorter to overlap util framePositions member
+    m_framePositions.clear();
+    m_framePositions.reserve(results.framePositions.size());
+    for (size_t i = 0; i < results.framePositions.size(); ++i)
+    {
+        m_framePositions.push_back(FramePositionAndNumber(results.framePositions[i], results.frameNumbers[i]));
+    }
+    cond = groupFramesByLogicalPosition();
+
+    // print frame groups if debug log level is enabled:
+    if (cond.good() && DCM_dcmsegLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+    {
+        DCMSEG_DEBUG("groupFramesByPosition(): Frames grouped by position:");
+        for (size_t i = 0; i < m_logicalFramePositions.size(); ++i)
+        {
+            OFStringStream ss;
+            for (size_t j = 0; j < m_logicalFramePositions[i].size(); ++j)
+            {
+                if (j > 0)
+                    ss << ", ";
+                ss << m_logicalFramePositions[i][j];
+            }
+            DCMSEG_DEBUG("groupFramesByPosition(): Logical frame #" << i << ": " << ss.str());
+        }
+    }
+    DCMSEG_DEBUG("groupFramesByPosition(): Grouping frames by position took " << tm.getDiff() << " s");
+
+    if (cond.bad())
+    {
+        m_framePositions.clear();
+        m_logicalFramePositions.clear();
+    }
+    return cond;
+}
+
+OFCondition OverlapUtil::getSegmentsByPosition(SegmentsByPosition& result)
+{
+    if (!m_seg)
+    {
+        DCMSEG_ERROR("getSegmentsByPosition(): No segmentation object set");
+        return EC_IllegalCall;
+    }
+    if (!m_segmentsByPosition.empty())
+    {
+        // Already computed
+        result = m_segmentsByPosition;
+        return EC_Normal;
+    }
+    // Make sure prerequisites are met
+    OFTimer tm;
+    OFCondition cond = groupFramesByPosition();
+    if (cond.bad())
+    {
+        return cond;
+    }
+    size_t numSegments = m_seg->getNumberOfSegments();
+    if (m_logicalFramePositions.empty())
+    {
+        cond = getFramesByPosition(m_logicalFramePositions);
+        if (cond.bad())
+            return cond;
+    }
+    m_segmentsByPosition.clear();
+    m_segmentsByPosition.resize(m_logicalFramePositions.size());
+    for (size_t l = 0; l < m_logicalFramePositions.size(); ++l)
+    {
+        OFVector<Uint32> segments;
+        for (size_t f = 0; f < m_logicalFramePositions[l].size(); ++f)
+        {
+            Uint32 frameNumber = m_logicalFramePositions[l][f];
+            OFVector<Uint32> segs;
+            FGBase* group         = NULL;
+            FGSegmentation* segFG = NULL;
+            group                 = m_seg->getFunctionalGroups().get(frameNumber, DcmFGTypes::EFG_SEGMENTATION);
+            segFG                 = OFstatic_cast(FGSegmentation*, group);
+            if (segFG)
+            {
+                Uint16 segNum = 0;
+                cond          = segFG->getReferencedSegmentNumber(segNum);
+                if (cond.good() && segNum > 0 && (segNum <= numSegments))
+                {
+                    // check if segment is already in the list for this position
+                    // (may happen if multiple frames for same segment are at same position?)
+                    OFBool found = OFFalse;
+                    for (size_t s = 0; s < m_segmentsByPosition[l].size(); ++s)
+                    {
+                        if (m_segmentsByPosition[l][s].m_segmentNumber == segNum)
+                        {
+                            found = OFTrue;
+                            break;
+                        }
+                    }
+                    if (!found)
+                    {
+                        m_segmentsByPosition[l].push_back(SegNumAndFrameNum(segNum, frameNumber));
+                    }
+                }
+                else if (segNum == 0)
+                {
+                    DCMSEG_ERROR(
+                        "getSegmentsByPosition(): Referenced Segment Number is 0 (not permitted), cannot add segment");
+                    cond = EC_InvalidValue;
+                    break;
+                }
+                else if (segNum > numSegments)
+                {
+                    DCMSEG_ERROR("getSegmentsByPosition(): Found Referenced Segment Number "
+                                 << segNum << " but only " << numSegments
+                                 << " segments are present, cannot add segment");
+                    DCMSEG_ERROR(
+                        "getSegmentsByPosition(): Segments are not numbered consecutively, cannot add segment");
+                    cond = EC_InvalidValue;
+                    break;
+                }
+                else
+                {
+                    DCMSEG_ERROR("getSegmentsByPosition(): Referenced Segment Number not found (not permitted) , "
+                                 "cannot add segment");
+                    cond = EC_TagNotFound;
+                    break;
+                }
+            }
+        }
+        if (cond.bad())
+        {
+            break;
+        }
+    }
+    // print segments per logical frame  if debug log level is enabled
+    if (cond.good() && DCM_dcmsegLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+    {
+        OFStringStream ss;
+        printSegmentsByPosition(ss);
+        DCMSEG_DEBUG(ss.str());
+    }
+    DCMSEG_DEBUG("groupFramesByPosition(): Grouping segments by position took " << tm.getDiff() << " s");
+    return cond;
+}
+
+OFCondition OverlapUtil::getOverlapMatrix(OverlapMatrix& matrix)
+{
+    if (!m_seg)
+    {
+        DCMSEG_ERROR("getOverlapMatrix(): No segmentation object set");
+        return EC_IllegalCall;
+    }
+    if (!m_segmentOverlapMatrix.empty())
+    {
+        // Already computed
+        matrix = m_segmentOverlapMatrix;
+        return EC_Normal;
+    }
+    // Make sure prerequisites are met
+    OFTimer tm;
+    SegmentsByPosition dontCare;
+    OFCondition result = getSegmentsByPosition(dontCare);
+    if (result.good())
+    {
+        result = buildOverlapMatrix();
+    }
+    if (result.good())
+    {
+        matrix = m_segmentOverlapMatrix;
+    }
+    DCMSEG_DEBUG("getOverlappingSegments(): Building overlap matrix took " << tm.getDiff() << " s");
+    return result;
+}
+
+OFCondition OverlapUtil::getNonOverlappingSegments(SegmentGroups& segmentGroups)
+{
+    if (!m_seg)
+    {
+        DCMSEG_ERROR("getNonOverlappingSegments(): No segmentation object set");
+        return EC_IllegalCall;
+    }
+    OFTimer tm;
+    OFCondition result;
+    if (!m_nonOverlappingSegments.empty())
+    {
+        // Already computed
+        segmentGroups = m_nonOverlappingSegments;
+        return EC_Normal;
+    }
+    // Make sure prerequisites are met
+    result = getOverlapMatrix(m_segmentOverlapMatrix);
+    if (result.good())
+    {
+        // Group those segments from the overlap matrix together, that do not
+        // overlap with each other.
+        // Go through all segments and check if they overlap with any of the already
+        // grouped segments. If not, add them to the same group. If yes, create a new group
+        // and add them there.
+        m_nonOverlappingSegments.push_back(OFVector<Uint32>());
+        for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+        {
+            // make sure we can cast this later to Uint32
+            if (i > OFnumeric_limits<Uint32>::max())
+            {
+                DCMSEG_ERROR("getNonOverlappingSegments(): Number of segments "
+                             << m_segmentOverlapMatrix.size()
+                             << " exceeds maximum number of possible segments (2^32-1)");
+                return EC_IllegalParameter;
+            }
+            // Loop over all groups and check whether the current segment overlaps with any of them
+            OFBool overlaps = OFFalse;
+            for (size_t j = 0; j < m_nonOverlappingSegments.size(); ++j)
+            {
+                // Loop over all segments in the current group
+                for (OFVector<Uint32>::iterator it = m_nonOverlappingSegments[j].begin();
+                     it != m_nonOverlappingSegments[j].end();
+                     ++it)
+                {
+                    // Check if the current segment overlaps with the segment in the current group
+                    if (m_segmentOverlapMatrix[i][(*it) - 1] == 1)
+                    {
+                        overlaps = OFTrue;
+                        break;
+                    }
+                }
+                if (!overlaps)
+                {
+                    // Add segment to current group
+                    m_nonOverlappingSegments[j].push_back(OFstatic_cast(Uint32, i) + 1);
+                    break;
+                }
+            }
+            if (overlaps)
+            {
+                // Create new group and add segment to it
+                m_nonOverlappingSegments.push_back(OFVector<Uint32>());
+                m_nonOverlappingSegments.back().push_back(OFstatic_cast(Uint32, i) + 1);
+            }
+        }
+    }
+    DCMSEG_DEBUG("getNonOverlappingSegments(): Grouping non-overlapping segments took " << tm.getDiff() << " s");
+    if (result.good())
+    {
+        // print non-overlapping segments if debug log level is enabled
+        if (DCM_dcmsegLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+        {
+            OFStringStream ss;
+            printNonOverlappingSegments(ss);
+            DCMSEG_DEBUG(ss.str());
+        }
+    }
+    if (result.good())
+    {
+        segmentGroups = m_nonOverlappingSegments;
+    }
+    return result;
+}
+
+OFBool OverlapUtil::hasOverlappingSegments()
+{
+    // Make sure prerequisites are met
+    OFCondition result = getOverlapMatrix(m_segmentOverlapMatrix);
+    if (result.good())
+    {
+        for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+        {
+            for (size_t j = 0; j < m_segmentOverlapMatrix[i].size(); ++j)
+            {
+                if (m_segmentOverlapMatrix[i][j] == 1)
+                {
+                    return OFTrue;
+                }
+            }
+        }
+    }
+    return OFFalse;
+}
+
+
+Float64 OverlapUtil::fabs(const Float64 value)
+{
+    return (value < 0) ? -value : value;
+}
+
+
+void OverlapUtil::printSegmentsByPosition(OFStringStream& ss)
+{
+    ss << "printSegmentsByPosition(): Segments grouped by logical frame positions, (seg#,frame#):" << OFendl;
+    for (size_t i = 0; i < m_segmentsByPosition.size(); ++i)
+    {
+        OFStringStream tempSS;
+        for (OFVector<SegNumAndFrameNum>::iterator it = m_segmentsByPosition[i].begin();
+             it != m_segmentsByPosition[i].end();
+             ++it)
+        {
+            if (it != m_segmentsByPosition[i].begin())
+                tempSS << ",";
+            tempSS << "(" << (*it).m_segmentNumber << "," << (*it).m_frameNumber << ")";
+        }
+        ss << "printSegmentsByPosition(): Logical frame #" << i << ": " << tempSS.str();
+    }
+}
+
+void OverlapUtil::printOverlapMatrix(OFStringStream& ss)
+{
+    ss << "printOverlapMatrix(): Overlap matrix:" << OFendl;
+    for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+    {
+        for (size_t j = 0; j < m_segmentOverlapMatrix[i].size(); ++j)
+        {
+            if (m_segmentOverlapMatrix[i][j] >= 0)
+                ss << OFstatic_cast(Uint32, m_segmentOverlapMatrix[i][j]);
+            else
+                ss << "1";
+            ss << " ";
+        }
+        ss << OFendl;
+    }
+}
+
+void OverlapUtil::printNonOverlappingSegments(OFStringStream& ss)
+{
+    ss << "printNonOverlappingSegments(): Non-overlapping segments:" << OFendl;
+    for (size_t i = 0; i < m_nonOverlappingSegments.size(); ++i)
+    {
+        ss << "Group #" << i << ": ";
+        for (OFVector<Uint32>::iterator it = m_nonOverlappingSegments[i].begin();
+             it != m_nonOverlappingSegments[i].end();
+             ++it)
+        {
+            if (it != m_nonOverlappingSegments[i].begin())
+                ss << ", ";
+            ss << (*it);
+        }
+        ss << OFendl;
+    }
+}
+
+OFCondition OverlapUtil::buildOverlapMatrix()
+{
+    // Make 2 dimensional array matrix of Sint8 type for (segment numbers) X (segment numbers).
+    // Initialize with -1 (not checked yet)
+    m_segmentOverlapMatrix.clear();
+    m_segmentOverlapMatrix.resize(m_seg->getNumberOfSegments());
+    for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+    {
+        m_segmentOverlapMatrix[i].resize(m_seg->getNumberOfSegments(), -1);
+    }
+    // Diagonal is always 0 (segment does not interfere/overlap with itself)
+    for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+    {
+        m_segmentOverlapMatrix[i][i] = 0;
+    }
+    // Go through all logical frame positions, and compare all segments at each position
+    size_t index1, index2;
+    index1 = index2 = 0;
+    for (size_t i = 0; i < m_segmentsByPosition.size(); ++i)
+    {
+        DCMSEG_TRACE("getOverlappingSegments(): Comparing segments at logical frame position " << i);
+        // Compare all segments at this position
+        for (OFVector<SegNumAndFrameNum>::iterator it = m_segmentsByPosition[i].begin();
+             it != m_segmentsByPosition[i].end();
+             ++it)
+        {
+            index1++;
+            for (OFVector<SegNumAndFrameNum>::iterator it2 = m_segmentsByPosition[i].begin();
+                 it2 != m_segmentsByPosition[i].end();
+                 ++it2)
+            {
+                index2++;
+                // Skip comparison of same segments in reverse order (index2 < index1)
+                if (index2 <= index1)
+                    continue;
+                // Skip self-comparison (diagonal is always 0); (index1==index2)
+                if (it->m_segmentNumber != it2->m_segmentNumber)
+                {
+                    // Check if we already have found an overlap on another logical frame, and if so, skip
+                    Sint8 existing_result
+                        = m_segmentOverlapMatrix[(*it).m_segmentNumber - 1][(*it2).m_segmentNumber - 1];
+                    if (existing_result == 1)
+                    {
+                        DCMSEG_DEBUG("getOverlappingSegments(): Skipping frame comparison on pos #"
+                                     << i << " for segments " << (*it).m_segmentNumber << " and "
+                                     << (*it2).m_segmentNumber << " (already marked as overlapping)");
+                        continue;
+                    }
+                    // Compare pixels of the frames referenced by each segments.
+                    // If they overlap, mark as overlapping
+                    OFBool overlap = OFFalse;
+                    checkFramesOverlap(it->m_frameNumber, it2->m_frameNumber, overlap);
+
+                    // Enter result into overlap matrix
+                    m_segmentOverlapMatrix[(*it).m_segmentNumber - 1][(*it2).m_segmentNumber - 1] = overlap ? 1 : 0;
+                    m_segmentOverlapMatrix[(*it2).m_segmentNumber - 1][(*it).m_segmentNumber - 1] = overlap ? 1 : 0;
+                }
+            }
+        }
+    }
+    // Since we don't compare all segments (since not all are showing up together on a single logical frame),
+    // we set all remaining entries that are still not initialized (-1) to 0 (no overlap)
+    for (size_t i = 0; i < m_segmentOverlapMatrix.size(); ++i)
+    {
+        for (size_t j = 0; j < m_segmentOverlapMatrix[i].size(); ++j)
+        {
+            if (m_segmentOverlapMatrix[i][j] == -1)
+            {
+                m_segmentOverlapMatrix[i][j] = 0;
+            }
+        }
+    }
+    // print overlap matrix if debug log level is enabled
+    if (DCM_dcmsegLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+    {
+        OFStringStream ss;
+        printOverlapMatrix(ss);
+        DCMSEG_DEBUG(ss.str());
+    }
+    return EC_Normal;
+}
+
+OFCondition OverlapUtil::checkFramesOverlap(const Uint32& f1, const Uint32& f2, OFBool& overlap)
+{
+    if (f1 == f2)
+    {
+        // The same frame should not be considered overlapping at all
+        overlap = OFFalse;
+        return EC_Normal;
+    }
+    overlap = OFFalse;
+    OFCondition result;
+    const DcmIODTypes::Frame<Uint8>* f1_data = OFstatic_cast(const DcmIODTypes::Frame<Uint8>*, m_seg->getFrame(f1));
+    const DcmIODTypes::Frame<Uint8>* f2_data = OFstatic_cast(const DcmIODTypes::Frame<Uint8>*, m_seg->getFrame(f2));
+    Uint16 rows, cols;
+    // Cast to DcmSegmentation base class (DcmIodImage)
+    rows = m_seg->getRows();
+    cols = m_seg->getColumns();
+    if (rows * cols % 8 != 0)
+    {
+        // We must compare pixel by pixel of the unpacked frames (for now)
+        result = checkFramesOverlapUnpacked(f1, f2, f1_data, f2_data, rows, cols, overlap);
+    }
+    else
+    {
+        // We can compare byte by byte using bitwise AND (if both have a 1 at the same position, they overlap)
+        result = checkFramesOverlapBinary(f1, f2, f1_data, f2_data, rows, cols, overlap);
+    }
+    if (result.good() && !overlap)
+    {
+        DCMSEG_TRACE("checkFramesOverlap(): Frames " << f1 << " and " << f2 << " don't overlap");
+    }
+    return result;
+}
+
+OFCondition OverlapUtil::checkFramesOverlapBinary(const Uint32& f1,
+                                                  const Uint32& f2,
+                                                  const DcmIODTypes::Frame<Uint8>* f1_data,
+                                                  const DcmIODTypes::Frame<Uint8>* f2_data,
+                                                  const Uint16& /* rows */,
+                                                  const Uint16& /* cols */,
+                                                  OFBool& overlap)
+{
+    DCMSEG_TRACE("checkFramesOverlap(): Comparing frames " << f1 << " and " << f2 << " for overlap (fast binary mode)");
+    if (!f1_data || !f2_data)
+    {
+        DCMSEG_ERROR("checkFramesOverlap(): Cannot access binary frames " << f1 << " and " << f2 << " for comparison");
+        return EC_IllegalCall;
+    }
+    if (f1_data->getLengthInBytes() != f2_data->getLengthInBytes())
+    {
+        DCMSEG_ERROR("checkFramesOverlap(): Frames " << f1 << " and " << f2
+                                                     << " have different length, cannot compare");
+        return EC_IllegalCall;
+    }
+    // Compare byte (8 pixels at once) using bitwise AND (if both have a 1 at the same position, they overlap)
+    for (size_t n = 0; n < f1_data->getLengthInBytes(); ++n)
+    {
+        if (f1_data->m_pixData[n] & f2_data->m_pixData[n])
+        {
+            DCMSEG_DEBUG("checkFramesOverlap(): Frames " << f1 << " and " << f2 << " do overlap, pixel value "
+                                                         << OFstatic_cast(Uint16, f1_data->m_pixData[n]) << " at index "
+                                                         << n << " is the same");
+            overlap = OFTrue;
+            break;
+        }
+    }
+    return EC_Normal;
+}
+
+OFCondition OverlapUtil::checkFramesOverlapUnpacked(const Uint32& f1,
+                                                    const Uint32& f2,
+                                                    const DcmIODTypes::Frame<Uint8>* f1_data,
+                                                    const DcmIODTypes::Frame<Uint8>* f2_data,
+                                                    const Uint16& rows,
+                                                    const Uint16 cols,
+                                                    OFBool& overlap)
+{
+    DCMSEG_TRACE("checkFramesOverlap(): Comparing frames " << f1 << " and " << f2
+                                                           << " for overlap (slow unpacked mode)");
+    OFunique_ptr<DcmIODTypes::Frame<Uint8> > f1_unpacked(DcmSegUtils::unpackBinaryFrame(f1_data, rows, cols));
+    OFunique_ptr<DcmIODTypes::Frame<Uint8> > f2_unpacked(DcmSegUtils::unpackBinaryFrame(f2_data, rows, cols));
+    if (!f1_unpacked || !f2_unpacked)
+    {
+        DCMSEG_ERROR("checkFramesOverlap(): Cannot unpack frames " << f1 << " and " << f2 << " for comparison");
+        return EC_IllegalCall;
+    }
+    if (f1_unpacked->getLengthInBytes() != f2_unpacked->getLengthInBytes())
+    {
+        DCMSEG_ERROR("checkFramesOverlap(): Frames " << f1 << " and " << f2
+                                                     << " have different length, cannot compare");
+        return EC_IllegalCall;
+    }
+    // Compare pixels of both frames and check whether at least one has the same value
+    DCMSEG_TRACE("checkFramesOverlap(): Comparing frames " << f1 << " and " << f2 << " for overlap");
+    for (size_t n = 0; n < f1_unpacked->getLengthInBytes(); ++n)
+    {
+        if (f1_unpacked->m_pixData[n] != 0 && (f1_unpacked->m_pixData[n] == f2_unpacked->m_pixData[n]))
+        {
+            DCMSEG_DEBUG("checkFramesOverlap(): Frames " << f1 << " and " << f2 << " do overlap, pixel value "
+                                                         << OFstatic_cast(Uint16, f1_unpacked->m_pixData[n])
+                                                         << " at index " << n << " is the same");
+            overlap = OFTrue;
+            break;
+        }
+    }
+    return EC_Normal;
+}
+
+
+OFCondition OverlapUtil::groupFramesByLogicalPosition()
+{
+    OFCondition cond;
+    FGInterface& fg = m_seg->getFunctionalGroups();
+    OFBool perFrame = OFFalse;
+    Float64 sliceThickness   = 0.0;
+    FGPixelMeasures* pm      = NULL;
+    FGBase* group            = fg.get(0, DcmFGTypes::EFG_PIXELMEASURES, perFrame);
+    pm = OFstatic_cast(FGPixelMeasures*, group);
+    if (pm)
+    {
+        // Get/compute Slice Thickness
+        cond = pm->getSliceThickness(sliceThickness);
+        if (cond.bad())
+        {
+            DCMSEG_ERROR("groupFramesByPosition(): Cannot get Slice Thickness from Pixel Measures FG: "
+                         << cond.text());
+            return cond;
+        }
+    }
+
+    Uint8 relevantCoordinate = identifyChangingCoordinate(m_imageOrientation);
+
+    // vec will contain all frame numbers that are at the same position
+    OFVector<Uint32> vec;
+    vec.push_back(m_framePositions[0].m_frameNumber);
+    m_logicalFramePositions.push_back(vec); // Initialize for first logical frame
+    for (size_t j = 1; j < m_framePositions.size(); ++j)
+    {
+        // If frame is close to previous frame, add it to the same vector.
+        // 2.5 is chosen since it means the frames are not further away if clearly less than half a slice
+        // thickness
+        Float64 diff = OverlapUtil::fabs(m_framePositions[j].m_position[relevantCoordinate]
+                            - m_framePositions[j - 1].m_position[relevantCoordinate]);
+        DCMSEG_DEBUG("Coordinates of both frames:");
+        DCMSEG_DEBUG("Frame " << j << ": " << m_framePositions[j].m_position[0] << ", "
+                                << m_framePositions[j].m_position[1] << ", "
+                                << m_framePositions[j].m_position[2]);
+        DCMSEG_DEBUG("Frame " << j - 1 << ": " << m_framePositions[j - 1].m_position[0] << ", "
+                                << m_framePositions[j - 1].m_position[1] << ", "
+                                << m_framePositions[j - 1].m_position[2]);
+        DCMSEG_DEBUG("groupFramesByPosition(): Frame " << j << " is " << diff
+                                                        << " mm away from previous frame");
+        // 1% inaccuracy for slice thickness will be considered as same logical position
+        if (diff < sliceThickness * 0.01)
+        {
+            // Add frame to last vector
+            DCMSEG_DEBUG("Assigning to same frame bucket as previous frame");
+            m_logicalFramePositions.back().push_back(
+                m_framePositions[j].m_frameNumber); // physical frame number
+        }
+        else
+        {
+            DCMSEG_DEBUG("Assigning to same new frame bucket");
+            // Create new vector
+            OFVector<Uint32> newVec;
+            newVec.push_back(m_framePositions[j].m_frameNumber);
+            m_logicalFramePositions.push_back(newVec);
+        }
+    }
+
+    return cond;
+}
+
+Uint8 OverlapUtil::identifyChangingCoordinate(const OFVector<Float64>& imageOrientation)
+{
+    Float64 cross_product[3];
+    // Compute cross product of image orientation vectors.
+    // We are only interested into the absolute values for later comparison
+    cross_product[0] = OverlapUtil::fabs(imageOrientation[1] * imageOrientation[5] - imageOrientation[2] * imageOrientation[4]);
+    cross_product[1] = OverlapUtil::fabs(imageOrientation[2] * imageOrientation[3] - imageOrientation[0] * imageOrientation[5]);
+    cross_product[2] = OverlapUtil::fabs(imageOrientation[0] * imageOrientation[4] - imageOrientation[1] * imageOrientation[3]);
+    // Find out which coordinate is changing the most (biggest absolute coordinate value of cross product)
+    if ((cross_product[0] > cross_product[1]) && (cross_product[0] > cross_product[2]))
+    {
+        return 0;
+    }
+    if ((cross_product[1] > cross_product[0]) && (cross_product[1] > cross_product[2]))
+    {
+        return 1;
+    }
+    if ((cross_product[2] > cross_product[0]) && (cross_product[2] > cross_product[1]))
+    {
+        return 2;
+    }
+    // No clear winner
+    return 3;
+}
index 387988867b05f7320e35512cfae13e136a69840a..396b30e443f6cbc40600670b2061e0205ed37e79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *
  *  All rights reserved.  See COPYRIGHT file for details.
  *
 
 #include "dcmtk/config/osconfig.h"
 
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dctypes.h"
 #include "dcmtk/dcmdata/dcuid.h"
+#include "dcmtk/dcmdata/dcxfer.h"
 #include "dcmtk/dcmfg/concatenationcreator.h"
 #include "dcmtk/dcmfg/fgderimg.h"
 #include "dcmtk/dcmfg/fgseg.h"
+#include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/dcmiod/iodutil.h"
 #include "dcmtk/dcmseg/segdoc.h"
 #include "dcmtk/dcmseg/segment.h"
 #include "dcmtk/dcmseg/segtypes.h"
 #include "dcmtk/dcmseg/segutils.h"
-#include "dcmtk/oflog/loglevel.h"
-#include <cstddef>
+#include "dcmtk/ofstd/ofutil.h"
 
-// default constructor (protected, instance creation via create() function)
-DcmSegmentation::DcmSegmentation()
-    : DcmSegmentation::IODImage(OFin_place<IODImagePixelModule<Uint8> >)
+
+struct DcmSegmentation::SetRowsAndCols
+{
+    SetRowsAndCols(const Uint16 rows, const Uint16 cols)
+        : m_rows(rows)
+        , m_cols(cols)
+    {
+    }
+
+    template <typename T>
+    OFCondition operator()(T& t)
+    {
+        t.setRows(m_rows);
+        t.setColumns(m_cols);
+        return EC_Normal;
+    }
+
+    // Members
+    const Uint16 m_rows;
+    const Uint16 m_cols;
+};
+
+
+struct DcmSegmentation::SetImagePixelModuleVisitor
+{
+    SetImagePixelModuleVisitor(const Uint16 rows, const Uint16 columns, const Uint16 bitsAllocated, const Uint16 bitsStored,
+                               const Uint16 highBit, const Uint16 samplesPerPixel, const OFString& photometricInterpretation)
+        : m_rows(rows)
+        , m_cols(columns)
+        , m_bitsAllocated(bitsAllocated)
+        , m_bitsStored(bitsStored)
+        , m_highBit(highBit)
+        , m_samplesPerPixel(samplesPerPixel)
+        , m_photometricInterpretation(photometricInterpretation)
+        , m_pixelRepresentation(2) // invalid default value
+    {
+    }
+
+    template <typename T>
+    OFCondition operator()(T& t)
+    {
+        if ((m_rows == 0) || (m_cols == 0))
+        {
+            DCMSEG_ERROR("Rows/Cols must be non-zero but are : " << m_rows << "/" << m_cols);
+            return IOD_EC_InvalidDimensions;
+        }
+
+        t.setRows(m_rows);
+        t.setColumns(m_cols);
+        t.setBitsAllocated(m_bitsAllocated);
+        t.setBitsStored(m_bitsStored);
+        t.setHighBit(m_highBit);
+        t.setSamplesPerPixel(m_samplesPerPixel);
+        t.setPhotometricInterpretation(m_photometricInterpretation);
+        t.setPixelRepresentation(OFis_signed<T>::value ? 1 : 0);
+
+        return EC_Normal;
+    }
+
+    // Members
+    const Uint16 m_rows;
+    const Uint16 m_cols;
+    const Uint16 m_bitsAllocated;
+    const Uint16 m_bitsStored;
+    const Uint16 m_highBit;
+    const Uint16 m_samplesPerPixel;
+    const OFString m_photometricInterpretation;
+    const Uint16 m_pixelRepresentation;
+
+};
+
+template <typename ImagePixel>
+DcmSegmentation::DcmSegmentation(OFin_place_type_t(ImagePixel))
+    : IODImage(OFin_place<ImagePixel>)
     , m_SegmentationSeries(DcmSegmentation::IODImage::getData(), DcmSegmentation::IODImage::getRules())
     , m_EnhancedGeneralEquipmentModule(DcmSegmentation::IODImage::getData(), DcmSegmentation::IODImage::getRules())
     , m_FG(DcmSegmentation::IODImage::getData(), DcmSegmentation::IODImage::getRules())
     , m_DimensionModule(DcmSegmentation::IODImage::getData(), DcmSegmentation::IODImage::getRules())
+    , m_PaletteColorLUTModule(DcmSegmentation::IODImage::getData(), DcmSegmentation::IODImage::getRules())
     , m_Frames()
+    , m_16BitPixelData(OFFalse)
+    , m_LabelmapColorModel(DcmSegTypes::SLCM_UNKNOWN)
     , m_ImageType("DERIVED\\PRIMARY")
     , m_ContentIdentificationMacro()
     , m_SegmentationType(DcmSegTypes::ST_BINARY)
@@ -48,6 +125,7 @@ DcmSegmentation::DcmSegmentation()
     , m_MaximumFractionalValue(DCM_MaximumFractionalValue)
     , m_Segments()
     , m_FGInterface()
+    , m_inputXfer(EXS_Unknown)
 {
     DcmSegmentation::initIODRules();
 }
@@ -57,35 +135,39 @@ void DcmSegmentation::initIODRules()
     // ------------ Segmentation Image Module -------------
 
     // Partly overrides rules from General Image Module
-    getRules()->addRule(new IODRule(DCM_ImageType, "2", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
-    getRules()->addRule(new IODRule(DCM_SegmentationType, "1", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
-                        OFTrue);
-    getRules()->addRule(
+    DcmSegmentation::IODImage::getRules()->addRule(
+        new IODRule(DCM_ImageType, "2", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    DcmSegmentation::IODImage::getRules()->addRule(
+        new IODRule(DCM_SegmentationType, "1", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    DcmSegmentation::IODImage::getRules()->addRule(
         new IODRule(DCM_SegmentationFractionalType, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
         OFTrue);
-    getRules()->addRule(
+    DcmSegmentation::IODImage::getRules()->addRule(
         new IODRule(DCM_MaximumFractionalValue, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    // Instance Number is Type 1 in Segmentation Image Module
+    DcmSegmentation::IODImage::getRules()->addRule(
+        new IODRule(DCM_InstanceNumber, "1", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+
 
     // Re-use General Image Module instead of Segmentation Image Module
-    getRules()->addRule(new IODRule(DCM_LossyImageCompression, "1", "1", "GeneralImageModule", DcmIODTypes::IE_IMAGE),
-                        OFTrue);
-    getRules()->addRule(
+    DcmSegmentation::IODImage::getRules()->addRule(
+        new IODRule(DCM_LossyImageCompression, "1", "1", "GeneralImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    DcmSegmentation::IODImage::getRules()->addRule(
         new IODRule(DCM_LossyImageCompressionMethod, "1-n", "1C", "GeneralImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
-    getRules()->addRule(
+    DcmSegmentation::IODImage::getRules()->addRule(
         new IODRule(DCM_LossyImageCompressionRatio, "1-n", "1C", "GeneralImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
 
-    // Override rule from General Series Module
-    getRules()->addRule(new IODRule(DCM_ReferencedPerformedProcedureStepSequence,
-                                    "1",
-                                    "1C",
-                                    "SegmentationSeriesModule",
-                                    DcmIODTypes::IE_SERIES),
-                        OFTrue);
-    getRules()->addRule(new IODRule(DCM_SeriesNumber, "1", "1", "SegmentationSeriesModule", DcmIODTypes::IE_SERIES),
-                        OFTrue);
+    // ------------ Segmentation Series Module -------------
 
-    // Instance Number is also used within Content Identification Macro, disable it there
-    m_ContentIdentificationMacro.getIODRules().deleteRule(DCM_InstanceNumber);
+    // Override rule from General Series Module
+    DcmSegmentation::IODImage::getRules()->addRule(new IODRule(DCM_ReferencedPerformedProcedureStepSequence,
+                                                               "1",
+                                                               "1C",
+                                                               "SegmentationSeriesModule",
+                                                               DcmIODTypes::IE_SERIES),
+                                                   OFTrue);
+    DcmSegmentation::IODImage::getRules()->addRule(
+        new IODRule(DCM_SeriesNumber, "1", "1", "SegmentationSeriesModule", DcmIODTypes::IE_SERIES), OFTrue);
 }
 
 DcmSegmentation::~DcmSegmentation()
@@ -94,35 +176,40 @@ DcmSegmentation::~DcmSegmentation()
 }
 
 // static method for loading segmentation objects
-OFCondition DcmSegmentation::loadFile(const OFString& filename, DcmSegmentation*& segmentation)
+OFCondition DcmSegmentation::loadFile(const OFString& filename, DcmSegmentation*& segmentation, const DcmSegmentation::LoadingFlags& flags)
 {
     DcmFileFormat dcmff;
     DcmDataset* dataset = NULL;
-    OFCondition result  = loadFile(dcmff, filename, dataset);
+    OFCondition result  = loadFile(dcmff, filename, dataset, flags.m_readTransferSyntax);
     if (result.bad())
         return result;
 
-    return loadDataset(*dataset, segmentation);
+    return loadDataset(*dataset, segmentation, flags);
 }
 
+
 // static method for loading segmentation objects
-OFCondition DcmSegmentation::loadDataset(DcmDataset& dataset, DcmSegmentation*& segmentation)
+OFCondition DcmSegmentation::loadDataset(DcmDataset& dataset, DcmSegmentation*& segmentation, const DcmSegmentation::LoadingFlags& flags)
 {
     segmentation       = NULL;
     OFCondition result = DcmSegmentation::decompress(dataset);
     if (result.bad())
         return result;
 
-    DcmSegmentation* temp = new DcmSegmentation();
-    if (temp == NULL)
+    DcmSegmentation *temp = NULL;
+    result = createRequiredBitDepth(dataset, temp);
+    if (result.bad())
     {
-        return EC_MemoryExhausted;
+        return result;
     }
-
+    // Apply the loading flags
+    temp->getFunctionalGroups().setUseThreads(flags.m_numThreads);
+    // Start actual reading
     result = temp->read(dataset);
     if (result.good())
     {
         segmentation = temp;
+        segmentation->m_inputXfer = dataset.getOriginalXfer();
     }
     else
     {
@@ -137,22 +224,29 @@ OFCondition DcmSegmentation::loadConcatenation(ConcatenationLoader& cl,
 {
     DcmDataset dset;
     segmentation = NULL;
-    OFVector<DcmIODTypes::Frame*> frames;
+    OFVector<DcmIODTypes::FrameBase*> frames;
     OFCondition result = cl.load(concatenationUID, &dset, frames);
     if (result.good())
     {
-        segmentation = new DcmSegmentation();
-        if (segmentation)
+        result = createRequiredBitDepth(dset, segmentation);
+        if (result.good())
         {
-            result = segmentation->readWithoutPixelData(dset);
-            if (result.good())
+            if (segmentation)
             {
-                segmentation->m_Frames = frames;
+                result = segmentation->readWithoutPixelData(dset);
+                if (result.good())
+                {
+                    segmentation->m_Frames = frames;
+                    // We don't check the transfer syntax in the input files,
+                    // so even all files had the same transfer syntax, we always
+                    // set it to EXS_Unknown.
+                    segmentation->m_inputXfer = EXS_Unknown;
+                }
+            }
+            else
+            {
+                result = EC_MemoryExhausted;
             }
-        }
-        else
-        {
-            result = EC_MemoryExhausted;
         }
     }
     if (result.bad())
@@ -170,7 +264,7 @@ OFCondition DcmSegmentation::createBinarySegmentation(DcmSegmentation*& segmenta
                                                       const ContentIdentificationMacro& contentIdentification)
 {
 
-    OFCondition result = createCommon(segmentation, rows, columns, equipmentInfo, contentIdentification);
+    OFCondition result = createCommon(segmentation, rows, columns, equipmentInfo, contentIdentification, 8);
     if (result.bad())
         return result;
 
@@ -179,6 +273,31 @@ OFCondition DcmSegmentation::createBinarySegmentation(DcmSegmentation*& segmenta
     return result;
 }
 
+
+OFCondition DcmSegmentation::createLabelmapSegmentation(DcmSegmentation *&segmentation,
+                                                        const Uint16 rows,
+                                                        const Uint16 columns,
+                                                        const IODGeneralEquipmentModule::EquipmentInfo &equipmentInfo,
+                                                        const ContentIdentificationMacro &contentIdentification,
+                                                        const OFBool use16Bit,
+                                                        const DcmSegTypes::E_SegmentationLabelmapColorModel colorModel)
+{
+    if (colorModel == DcmSegTypes::SLCM_UNKNOWN)
+    {
+        DCMSEG_ERROR("Cannot create labelmap segmentation: Color model not set");
+        return EC_IllegalParameter;
+    }
+
+    OFCondition result = createCommon(segmentation, rows, columns, equipmentInfo, contentIdentification, use16Bit ? 16 : 8);
+    if (result.bad())
+        return result;
+
+    segmentation->m_SegmentationType = DcmSegTypes::ST_LABELMAP;
+    segmentation->m_16BitPixelData = use16Bit;
+    segmentation->m_LabelmapColorModel = colorModel;
+    return result;
+}
+
 OFCondition DcmSegmentation::createFractionalSegmentation(DcmSegmentation*& segmentation,
                                                           const Uint16 rows,
                                                           const Uint16 columns,
@@ -187,7 +306,7 @@ OFCondition DcmSegmentation::createFractionalSegmentation(DcmSegmentation*& segm
                                                           const IODGeneralEquipmentModule::EquipmentInfo& equipmentInfo,
                                                           const ContentIdentificationMacro& contentIdentification)
 {
-    OFCondition result = createCommon(segmentation, rows, columns, equipmentInfo, contentIdentification);
+    OFCondition result = createCommon(segmentation, rows, columns, equipmentInfo, contentIdentification, 8);
     if (result.bad())
         return result;
 
@@ -202,7 +321,8 @@ OFCondition DcmSegmentation::createCommon(DcmSegmentation*& segmentation,
                                           const Uint16 rows,
                                           const Uint16 columns,
                                           const IODGeneralEquipmentModule::EquipmentInfo& equipmentInfo,
-                                          const ContentIdentificationMacro& contentIdentification)
+                                          const ContentIdentificationMacro& contentIdentification,
+                                          const Uint16 bitsAllocated)
 {
     if ((rows == 0) || (columns == 0))
     {
@@ -210,27 +330,19 @@ OFCondition DcmSegmentation::createCommon(DcmSegmentation*& segmentation,
         return EC_IllegalParameter;
     }
 
-    segmentation = new DcmSegmentation();
+    OFCondition result = createRequiredBitDepth(bitsAllocated, segmentation);
     if (segmentation == NULL)
         return EC_MemoryExhausted;
 
     segmentation->getImagePixel().setRows(rows);
     segmentation->getImagePixel().setColumns(columns);
 
-    OFCondition result = segmentation->setContentIdentification(contentIdentification);
+    DCMSEG_DEBUG("Setting segmentation content identification");
+    result = segmentation->setContentIdentification(contentIdentification);
     if (result.good())
     {
-        OFString tempstr;
-        contentIdentification.getInstanceNumber(tempstr);
-        result = segmentation->getGeneralImage().setInstanceNumber(tempstr);
-        if (result.bad())
-        {
-            delete segmentation;
-            segmentation = NULL;
-            return EC_InvalidValue;
-        }
-
         DcmIODUtil::setContentDateAndTimeNow(segmentation->getGeneralImage());
+        DCMSEG_DEBUG("Setting segmentation equipment information");
         result = segmentation->setEquipmentInfo(equipmentInfo, OFTrue /* check */);
     }
 
@@ -243,6 +355,44 @@ OFCondition DcmSegmentation::createCommon(DcmSegmentation*& segmentation,
     return result;
 }
 
+OFCondition DcmSegmentation::createRequiredBitDepth(const Uint16 bitsAllocated, DcmSegmentation*& seg)
+{
+    OFCondition result;
+    seg = NULL;
+    if (bitsAllocated == 16)
+    {
+        seg = new DcmSegmentation(OFin_place<IODImagePixelModule<Uint16> >);
+    }
+    else if ( (bitsAllocated == 8) || (bitsAllocated == 1) )
+    {
+        seg = new DcmSegmentation(OFin_place<IODImagePixelModule<Uint8> >);
+    }
+    else
+    {
+        DCMSEG_ERROR("Cannot read segmentation object: Bits Allocated is neither 8 nor 16");
+        result = IOD_EC_InvalidPixelData;
+    }
+    if (result.good() && (seg == NULL))
+    {
+        result = EC_MemoryExhausted;
+    }
+    return result;
+
+}
+
+OFCondition DcmSegmentation::createRequiredBitDepth(DcmItem& item, DcmSegmentation*& seg)
+{
+    Uint16 bitsAllocated = 0;
+    OFCondition result = item.findAndGetUint16(DCM_BitsAllocated, bitsAllocated);
+    if (result.bad())
+    {
+        DCMSEG_ERROR("Cannot read Bits Allocated from dataset: " << result.text());
+        return result;
+    }
+    return createRequiredBitDepth(bitsAllocated, seg);
+}
+
+
 FGDerivationImage*
 DcmSegmentation::createDerivationImageFG(const OFVector<ImageSOPInstanceReferenceMacro>& derivationImages,
                                          const OFString& derivationDescription)
@@ -264,14 +414,17 @@ OFCondition DcmSegmentation::read(DcmItem& dataset)
 OFCondition DcmSegmentation::readWithoutPixelData(DcmItem& dataset)
 {
     OFString sopClass;
-    if (DcmIODUtil::checkSOPClass(&dataset, UID_SegmentationStorage, sopClass).bad())
+    if (DcmIODUtil::checkSOPClass(&dataset, UID_SegmentationStorage, sopClass).bad()
+    && DcmIODUtil::checkSOPClass(&dataset, UID_LabelMapSegmentationStorage, sopClass).bad())
     {
         DCMSEG_ERROR("Given file does not seem to be a segmentation storage object since SOP class is: " << sopClass);
         return IOD_EC_WrongSOPClass;
     }
 
     // Read attributes in base classes
-    DcmSegmentation::IODImage::read(dataset);
+    OFCondition result = DcmSegmentation::IODImage::read(dataset);
+    if (result.bad())
+        DCMSEG_WARN("Problem with reading Image Pixel attributes: " << result.text() << " (ignoring)");
 
     // Read Segmentation Series Module
     m_SegmentationSeries.read(dataset);
@@ -294,13 +447,24 @@ OFCondition DcmSegmentation::readWithoutPixelData(DcmItem& dataset)
 
     readSegments(dataset);
 
-    readSegmentationFractionalType(dataset);
+    if (m_SegmentationType == DcmSegTypes::ST_FRACTIONAL)
+        readSegmentationFractionalType(dataset);
 
     m_ContentIdentificationMacro.read(dataset);
 
+    // Read Photometric Interpretation and check whether it fits the segmentation type
+    OFString colorModel;
+    if (dataset.findAndGetOFString(DCM_PhotometricInterpretation, colorModel).good() && (colorModel == "PALETTE COLOR"))
+    {
+        // For palette, read Palette Color LUT Module and ICC Profile Module
+        m_PaletteColorLUTModule.read(dataset);
+        m_ICCProfileModule.read(dataset);
+    }
+    checkColorModel(colorModel);
+
     // Read specific segmentation elements
     DcmIODUtil::getAndCheckElementFromDataset(
-        dataset, m_MaximumFractionalValue, getRules()->getByTag(DCM_MaximumFractionalValue));
+        dataset, m_MaximumFractionalValue, DcmSegmentation::IODImage::getRules()->getByTag(DCM_MaximumFractionalValue));
 
     return EC_Normal;
 }
@@ -315,6 +479,16 @@ OFBool DcmSegmentation::getCheckFGOnWrite()
     return m_FGInterface.getCheckOnWrite();
 }
 
+void DcmSegmentation::setValueCheckOnWrite(const OFBool doCheck)
+{
+    m_SegmentationSeries.setValueCheckOnWrite(doCheck);
+    m_EnhancedGeneralEquipmentModule.setValueCheckOnWrite(doCheck);
+    m_PaletteColorLUTModule.setValueCheckOnWrite(doCheck);
+    m_DimensionModule.setValueCheckOnWrite(doCheck);
+    m_ICCProfileModule.setValueCheckOnWrite(doCheck);
+    DcmSegmentation::IODImage::setValueCheckOnWrite(doCheck);
+}
+
 void DcmSegmentation::setCheckDimensionsOnWrite(const OFBool doCheck)
 {
     m_DimensionModule.setCheckOnWrite(doCheck);
@@ -325,6 +499,11 @@ OFBool DcmSegmentation::getCheckDimensionsOnWrite()
     return m_DimensionModule.getCheckOnWrite();
 }
 
+E_TransferSyntax DcmSegmentation::getInputTransferSyntax() const
+{
+    return m_inputXfer;
+}
+
 OFCondition DcmSegmentation::writeWithSeparatePixelData(DcmItem& dataset, Uint8*& pixData, size_t& pixDataLength)
 {
     // FGInterface::write() will know whether it has to check FG structure
@@ -337,9 +516,134 @@ OFCondition DcmSegmentation::writeWithSeparatePixelData(DcmItem& dataset, Uint8*
     OFCondition result;
 
     // -- Set constant default values written by external modules --
-    getGeneralImage().setLossyImageCompression("00");
-    getGeneralImage().setImageType(m_ImageType);
-    getSOPCommon().setSOPClassUID(UID_SegmentationStorage);
+    DcmSegmentation::IODImage::getGeneralImage().setLossyImageCompression("00");
+    DcmSegmentation::IODImage::getGeneralImage().setImageType(m_ImageType);
+    // Set Instance Number if not set
+    OFString InstanceNumber;
+    getData()->findAndGetOFString(DCM_InstanceNumber, InstanceNumber);
+    if (InstanceNumber.empty())
+    {
+        DcmSegmentation::IODImage::getGeneralImage().setInstanceNumber("1");
+    }
+
+    // Set SOP Class UID based on segmentation type
+    setSOPClassUIDBasedOnSegmentationType();
+
+    // -- Extra Study level data --
+
+    // Enhanced Equipment Module
+    if (result.good())
+        result = m_EnhancedGeneralEquipmentModule.write(dataset);
+
+    // -- Extra Series level data --
+
+    // Write segmentation-specific series level attribute (Segmentation Series Module)
+    if (result.good())
+        result = m_SegmentationSeries.write(dataset);
+
+    // -- Extra Image level data --
+
+    // Write Multi-Frame Functional Groups Module
+    if (result.good())
+        result = writeMultiFrameFunctionalGroupsModule(dataset);
+
+    // Write Multi-Frame Dimension Module
+    if (result.good())
+        result = writeMultiFrameDimensionModule(dataset);
+
+    // Write Palette Color Lookup Table Module and ICC Profile Module
+    if (result.good())
+    {
+        if (m_LabelmapColorModel == DcmSegTypes::SLCM_PALETTE)
+        {
+            result = m_PaletteColorLUTModule.write(dataset);
+            if (result.good())
+            {
+                result = m_ICCProfileModule.write(dataset);
+            }
+        }
+    }
+
+    // Write segmentation image module and image pixel module
+    if (result.good())
+        result = writeSegmentationImageModule(dataset);
+
+    // -- Write common multi frame image IOD attributes --
+
+    // Patient Module
+    // General Study Module
+    // General Series Module
+    // Frame of Reference Module
+    // General Equipment Module
+    // General Image Module
+    // Multi-frame Functional Groups Module (except functional groups itself)
+    // SOP Common Module
+    // Common Instance Reference Module
+    if (result.good())
+        result = DcmSegmentation::IODImage::write(dataset);
+
+    // Write frame pixel data
+    if (result.good())
+    {
+        Uint32 numFrames = DcmIODUtil::limitMaxFrames(
+            m_Frames.size(), "More than 2147483647 frames provided, will only write 2147483647");
+        Uint16 rows, cols, bytesPerPixel;
+        rows = cols = bytesPerPixel = 0;
+        DcmSegmentation::getImagePixel().getRows(rows);
+        DcmSegmentation::getImagePixel().getColumns(cols);
+        DcmSegmentation::getImagePixel().getBitsAllocated(bytesPerPixel);
+        if (bytesPerPixel >= 8) // 8 or 16
+        {
+            bytesPerPixel = bytesPerPixel / 8;
+        }
+        result = getTotalBytesRequired(rows, cols, bytesPerPixel, numFrames, pixDataLength);
+        if (result.bad())
+            return result;
+
+        pixData = new Uint8[pixDataLength];
+        if (!pixData)
+            return EC_MemoryExhausted;
+
+        switch (m_SegmentationType)
+        {
+            case DcmSegTypes::ST_BINARY:
+                result = writeBinaryFrames(pixData, rows, cols, pixDataLength);
+                break;
+            case DcmSegTypes::ST_FRACTIONAL:
+            case DcmSegTypes::ST_LABELMAP:
+                result = writeByteBasedFrames(pixData);
+                break;
+            default:
+                result = SG_EC_UnknownSegmentationType;
+        }
+        if (result.bad())
+        {
+            delete[] pixData;
+        }
+    }
+
+    return result;
+}
+
+OFCondition DcmSegmentation::writeWithSeparatePixelData(DcmItem& dataset, Uint16*& pixData, size_t& numPixelDataBytes)
+{
+    // FGInterface::write() will know whether it has to check FG structure
+    // so we do not need to check FG structure here (OFFalse).
+    if (!check(OFFalse))
+    {
+        return IOD_EC_InvalidObject;
+    }
+
+    OFCondition result;
+
+    // -- Set constant default values written by external modules --
+
+    DcmSegmentation::IODImage::getGeneralImage().setLossyImageCompression("00");
+    // Labelmap segmentations have a different SOP Class UID
+    DcmSegmentation::IODImage::getGeneralImage().setImageType(m_ImageType);
+
+    // Set SOP Class UID based on segmentation type
+    setSOPClassUIDBasedOnSegmentationType();
 
     // -- Extra Study level data --
 
@@ -363,6 +667,19 @@ OFCondition DcmSegmentation::writeWithSeparatePixelData(DcmItem& dataset, Uint8*
     if (result.good())
         result = writeMultiFrameDimensionModule(dataset);
 
+    // Write Palette Color Lookup Table Module and ICC Profile Module
+    if (result.good())
+    {
+        if (m_LabelmapColorModel == DcmSegTypes::SLCM_PALETTE)
+        {
+            result = m_PaletteColorLUTModule.write(dataset);
+            if (result.good())
+            {
+                result = m_ICCProfileModule.write(dataset);
+            }
+        }
+    }
+
     // Write segmentation image module and image pixel module
     if (result.good())
         result = writeSegmentationImageModule(dataset);
@@ -386,24 +703,39 @@ OFCondition DcmSegmentation::writeWithSeparatePixelData(DcmItem& dataset, Uint8*
     {
         Uint32 numFrames = DcmIODUtil::limitMaxFrames(
             m_Frames.size(), "More than 2147483647 frames provided, will only write 2147483647");
-        Uint16 rows, cols;
-        rows = cols = 0;
+        Uint16 rows, cols, bytesPerPixel;
+        rows = cols = bytesPerPixel = 0;
         getImagePixel().getRows(rows);
         getImagePixel().getColumns(cols);
-        result = getTotalBytesRequired(rows, cols, numFrames, pixDataLength);
+        getImagePixel().getBitsAllocated(bytesPerPixel);
+        if (bytesPerPixel >= 8) // 8 or 16
+        {
+            bytesPerPixel = bytesPerPixel / 8;
+        }
+        result = getTotalBytesRequired(rows, cols, bytesPerPixel, numFrames, numPixelDataBytes);
         if (result.bad())
             return result;
 
-        pixData = new Uint8[pixDataLength];
+        pixData = new Uint16[numPixelDataBytes / 2]; // 16 bit data
         if (!pixData)
             return EC_MemoryExhausted;
 
-        if (m_SegmentationType == DcmSegTypes::ST_BINARY)
-            result = writeBinaryFrames(pixData, rows, cols, pixDataLength);
-        else if (m_SegmentationType == DcmSegTypes::ST_FRACTIONAL)
-            result = writeFractionalFrames(pixData);
-        else
-            result = SG_EC_UnknownSegmentationType;
+        switch (m_SegmentationType)
+        {
+            case DcmSegTypes::ST_BINARY:
+                DCMSEG_ERROR("Binary segmentations must be instantiated with 8 bit pixel data (Uint8)");
+                result = IOD_EC_InvalidPixelData;
+                break;
+            case DcmSegTypes::ST_FRACTIONAL:
+                DCMSEG_ERROR("Fractional segmentations must be instantiated with 8 bit pixel data (Uint8)");
+                result = IOD_EC_InvalidPixelData;
+                break;
+            case DcmSegTypes::ST_LABELMAP:
+                result = writeByteBasedFrames(pixData);
+                break;
+            default:
+                result = SG_EC_UnknownSegmentationType;
+        }
         if (result.bad())
         {
             delete[] pixData;
@@ -428,6 +760,25 @@ size_t DcmSegmentation::getNumberOfFrames()
     return m_FGInterface.getNumberOfFrames();
 }
 
+OFBool DcmSegmentation::has16BitPixelData() const
+{
+    return this->m_16BitPixelData;
+}
+
+Uint16 DcmSegmentation::getRows()
+{
+    Uint16 rows = 0;
+    DcmSegmentation::getImagePixel().getRows(rows);
+    return rows;
+}
+
+Uint16 DcmSegmentation::getColumns()
+{
+    Uint16 cols = 0;
+    DcmSegmentation::getImagePixel().getColumns(cols);
+    return cols;
+}
+
 size_t DcmSegmentation::getNumberOfSegments()
 {
     return m_Segments.size();
@@ -445,7 +796,6 @@ IODSegmentationSeriesModule& DcmSegmentation::getSegmentationSeriesModule()
 
 OFCondition DcmSegmentation::addSegment(DcmSegment* seg, Uint16& segmentNumber)
 {
-    segmentNumber = 0;
     if (seg == NULL)
         return EC_IllegalParameter;
 
@@ -453,77 +803,35 @@ OFCondition DcmSegmentation::addSegment(DcmSegment* seg, Uint16& segmentNumber)
     {
         return SG_EC_MaxSegmentsReached;
     }
-
-    // Casting is safe since we made sure number of segments fits into 16 bit
-    segmentNumber = OFstatic_cast(Uint16, m_Segments.size() + 1);
-    m_Segments.push_back(seg);
-    return EC_Normal;
-}
-
-OFCondition DcmSegmentation::addFrame(Uint8* pixData)
-{
-    if (m_Frames.size() >= DCM_SEG_MAX_FRAMES)
-        return SG_EC_MaxFramesReached;
-
-    OFCondition result;
-    Uint16 rows = 0;
-    Uint16 cols = 0;
-    if (getImagePixel().getRows(rows).good() && getImagePixel().getColumns(cols).good())
+    // For labelmaps, use the given segment number
+    if (m_SegmentationType == DcmSegTypes::ST_LABELMAP)
     {
-        DcmIODTypes::Frame* frame = NULL;
-        if (m_SegmentationType == DcmSegTypes::ST_BINARY)
-        {
-            frame = DcmSegUtils::packBinaryFrame(pixData, rows, cols);
-            if (!frame)
-            {
-                result = IOD_EC_CannotInsertFrame;
-            }
-            // with debug logging enabled, print out the binary frame
-            if (DCM_dcmsegLogger.isEnabledFor(dcmtk::log4cplus::DEBUG_LOG_LEVEL))
-            {
-                DCMSEG_DEBUG("Added binary segmentation frame:");
-                DcmSegUtils::debugDumpBin(frame->pixData, frame->length, "Binary frame", OFTrue);
-            }
-        }
-        else // fractional
-        {
-            frame = new DcmIODTypes::Frame();
-            if (frame)
-            {
-                frame->length  = rows * cols;
-                frame->pixData = new Uint8[frame->length];
-                if (frame->pixData)
-                {
-                    memcpy(frame->pixData, pixData, frame->length);
-                }
-                else
-                {
-                    delete frame;
-                    result = EC_MemoryExhausted;
-                }
-            }
-            else
-                result = EC_MemoryExhausted;
-        }
-        if (result.good())
-        {
-            m_Frames.push_back(frame);
-        }
+        m_Segments.insert(OFMake_pair(segmentNumber, seg));
+        return EC_Normal;
     }
-    else
+    // For binary/fractional, start with 1 if no segment exists
+    if (m_Segments.empty())
     {
-        DCMSEG_ERROR("Cannot add frame since rows and/or columns are unknown");
-        result = IOD_EC_CannotInsertFrame;
+        segmentNumber = 1;
+        m_Segments.insert(OFMake_pair(segmentNumber, seg));
+        return EC_Normal;
     }
-    return result;
+    // Use next free segment number and insert
+    // (i.e. get the highest segment number and increment by 1).
+    OFMap<Uint16, DcmSegment*>::iterator it = m_Segments.end();
+    it--;
+    segmentNumber = it->first + 1;
+    m_Segments.insert(OFMake_pair(segmentNumber, seg));
+    return EC_Normal;
 }
 
+
 SOPInstanceReferenceMacro& DcmSegmentation::getReferencedPPS()
 {
-    return getSeries().getReferencedPPS();
+    return DcmSegmentation::IODImage::getSeries().getReferencedPPS();
 }
 
-const DcmIODTypes::Frame* DcmSegmentation::getFrame(const size_t& frameNo)
+const DcmIODTypes::FrameBase* DcmSegmentation::getFrame(const size_t& frameNo)
 {
     if (frameNo > m_Frames.size() - 1)
     {
@@ -561,83 +869,6 @@ OFCondition DcmSegmentation::addForAllFrames(const FGBase& group)
     return m_FGInterface.addShared(group);
 }
 
-OFCondition
-DcmSegmentation::addFrame(Uint8* pixData, const Uint16 segmentNumber, const OFVector<FGBase*>& perFrameInformation)
-{
-    if (m_Frames.size() >= DCM_SEG_MAX_FRAMES)
-        return SG_EC_MaxFramesReached;
-
-    Uint32 frameNo = OFstatic_cast(Uint32, m_Frames.size()); // will be the index of the frame (counted from 0)
-    OFCondition result;
-
-    // Check input parameters
-    if (pixData == NULL)
-    {
-        DCMSEG_ERROR("No pixel data provided or zero length");
-        result = EC_IllegalParameter;
-    }
-    if (segmentNumber > m_Segments.size())
-    {
-        DCMSEG_ERROR("Cannot add frame: Segment with given number " << segmentNumber << " does not exist");
-        result = SG_EC_NoSuchSegment;
-    }
-    if (result.bad())
-        return result;
-
-    OFVector<FGBase*>::const_iterator it = perFrameInformation.begin();
-    while (it != perFrameInformation.end())
-    {
-        result = (*it)->check();
-        if (result.bad())
-        {
-            DCMSEG_ERROR("Could not add new frame since functional group of type: "
-                         << (*it)->getType() << " is invalid: " << result.text());
-            break;
-        }
-        result = m_FGInterface.addPerFrame(frameNo, *(*it));
-        if (result.bad())
-        {
-            DCMSEG_ERROR("Could not add new frame since functional group of type " << (*it)->getType() << ": "
-                                                                                   << result.text());
-            break;
-        }
-        it++;
-    }
-
-    // Now also add Segmentation Functional Group
-    if (result.good())
-    {
-        FGSegmentation seg;
-        result = seg.setReferencedSegmentNumber(segmentNumber);
-        if (result.good())
-        {
-            result = m_FGInterface.addPerFrame(frameNo, seg);
-        }
-        else
-        {
-            DCMSEG_ERROR("Could not add new frame, invalid segment number " << segmentNumber << ": " << result.text());
-        }
-    }
-
-    // Insert pixel data
-    if (result.good())
-    {
-        result = addFrame(pixData);
-    }
-
-    // Cleanup any per-frame groups that might have been inserted and return
-    if (result.bad())
-    {
-        for (OFVector<FGBase*>::const_iterator it2 = perFrameInformation.begin(); it2 != perFrameInformation.end();
-             it2++)
-        {
-            m_FGInterface.deletePerFrame(frameNo, (*it2)->getType());
-        }
-    }
-
-    return result;
-}
-
 ContentIdentificationMacro& DcmSegmentation::getContentIdentification()
 {
     return m_ContentIdentificationMacro;
@@ -648,14 +879,24 @@ IODMultiframeDimensionModule& DcmSegmentation::getDimensions()
     return m_DimensionModule;
 }
 
+IODPaletteColorLUTModule& DcmSegmentation::getPaletteColorLUT()
+{
+    return m_PaletteColorLUTModule;
+}
+
+IODICCProfileModule& DcmSegmentation::getICCProfile()
+{
+    return m_ICCProfileModule;
+}
+
 OFCondition
 DcmSegmentation::setLossyImageCompressionFlag(const OFString& ratios, const OFString& methods, const OFBool checkValues)
 {
-    OFCondition result = getGeneralImage().setLossyImageCompression("01");
+    OFCondition result = DcmSegmentation::IODImage::getGeneralImage().setLossyImageCompression("01");
     if (result.good() || !checkValues)
-        result = getGeneralImage().setLossyImageCompressionMethod(methods);
+        result = DcmSegmentation::IODImage::getGeneralImage().setLossyImageCompressionMethod(methods);
     if (result.good() || !checkValues)
-        result = getGeneralImage().setLossyImageCompressionRatio(ratios);
+        result = DcmSegmentation::IODImage::getGeneralImage().setLossyImageCompressionRatio(ratios);
 
     if (checkValues)
         return result;
@@ -672,25 +913,37 @@ OFCondition DcmSegmentation::saveFile(const OFString& filename, const E_Transfer
 #endif
     )
     {
-        DcmXfer ts(writeXfer);
+        if ((writeXfer == EXS_RLELossless) && (m_SegmentationType != DcmSegTypes::ST_LABELMAP))
+        {
+            DcmXfer ts(writeXfer);
 #ifdef WITH_ZLIB
-        DCMSEG_ERROR("Cannot write transfer syntax: " << ts.getXferName()
+            DCMSEG_ERROR("Cannot write transfer syntax: " << ts.getXferName()
                                                       << ": Can only write uncompressed or Deflated)");
 #else
-        if (writeXfer == EXS_DeflatedLittleEndianExplicit)
-        {
-            DCMSEG_ERROR("Cannot write transfer syntax: "
-                         << ts.getXferName() << ": Deflate (ZLIB) support disabled, can only write uncompressed");
-        }
+            if (writeXfer == EXS_DeflatedLittleEndianExplicit)
+            {
+                DCMSEG_ERROR("Cannot write transfer syntax: "
+                             << ts.getXferName() << ": Deflate (ZLIB) support disabled");
+            }
 #endif
-        return EC_CannotChangeRepresentation;
+            return EC_CannotChangeRepresentation;
+        }
     }
 
     DcmFileFormat dcmff;
     OFCondition result = writeDataset(*(dcmff.getDataset()));
     if (result.good())
     {
-        result = dcmff.saveFile(filename.c_str(), writeXfer);
+        if (dcmff.chooseRepresentation(writeXfer, NULL).good() && dcmff.getDataset()->canWriteXfer(writeXfer))
+        {
+            result = dcmff.saveFile(filename.c_str(), writeXfer, EET_ExplicitLength);
+        }
+        else
+        {
+            DcmXfer ts(writeXfer);
+            DCMSEG_ERROR("Cannot write transfer syntax: " << ts.getXferName());
+            result = EC_CannotChangeRepresentation;
+        }
     }
     if (result.bad())
     {
@@ -745,34 +998,46 @@ OFCondition DcmSegmentation::setContentIdentification(const ContentIdentificatio
 
 /* -- Getter for DICOM attributes -- */
 
-DcmSegment* DcmSegmentation::getSegment(const size_t segmentNumber)
+DcmSegment* DcmSegmentation::getSegment(const Uint16 segmentNumber)
 {
     // check for invalid index
-    if ((segmentNumber == 0) || (segmentNumber > m_Segments.size()))
+    if ( (m_SegmentationType != DcmSegTypes::ST_LABELMAP) && (segmentNumber == 0)  )
+    {
+        DCMSEG_ERROR("Cannot get segment 0: No such Segment Number allowed segmentation if segmentation is of type " << DcmSegTypes::segtype2OFString(m_SegmentationType));
+        return NULL;
+    }
+    OFMap<Uint16, DcmSegment*>::iterator it = m_Segments.find(segmentNumber);
+    if (it == m_Segments.end())
     {
         return NULL;
     }
 
-    // logical segment numbering starts with 1, so subtract 1 for vector index
-    return m_Segments[segmentNumber - 1];
+    return it->second;
 }
 
 OFBool DcmSegmentation::getSegmentNumber(const DcmSegment* segment, size_t& segmentNumber)
 {
-    segmentNumber = 0;
-    size_t max    = m_Segments.size();
-    for (size_t count = 0; count < max; count++)
+    if (segment == NULL)
+        return OFFalse;
+
+    OFMap<Uint16, DcmSegment*>::iterator it = m_Segments.begin();
+    while (it != m_Segments.end())
     {
-        if (m_Segments.at(count) == segment)
+        if (it->second == segment)
         {
-            segmentNumber = OFstatic_cast(Uint16, count + 1);
+            segmentNumber = it->first;
             return OFTrue;
         }
+        it++;
     }
-    // not found
     return OFFalse;
 }
 
+const OFMap<Uint16, DcmSegment*>& DcmSegmentation::getSegments()
+{
+    return m_Segments;
+}
+
 OFCondition DcmSegmentation::getModality(OFString& value, const long signed int pos) const
 {
     (void)pos;
@@ -809,15 +1074,51 @@ OFCondition DcmSegmentation::importFromSourceImage(DcmItem& dataset, const bool
 OFCondition DcmSegmentation::writeSegments(DcmItem& item)
 {
     OFCondition result;
+    // writeSubSequence cannot handle a map, copy to vector instead and use that for this purpose
+    OFVector<DcmSegment*> segments;
+    OFMap<Uint16, DcmSegment*>::iterator it = m_Segments.begin();
+    while (it != m_Segments.end())
+    {
+        segments.push_back(it->second);
+        it++;
+    }
     DcmIODUtil::writeSubSequence<OFVector<DcmSegment*> >(
-        result, DCM_SegmentSequence, m_Segments, item, "1-n", "1", "SegmentationImageModule");
+        result, DCM_SegmentSequence, segments, item, "1-n", "1", "SegmentationImageModule");
     return result;
 }
 
 OFCondition DcmSegmentation::readSegments(DcmItem& item)
 {
-    return DcmIODUtil::readSubSequence<OFVector<DcmSegment*> >(
-        item, DCM_SegmentSequence, m_Segments, "1-n", "1", "SegmentationImageModule");
+    // readSubSequence cannot handle a map, read into vector instead and fill into map afterwards
+    OFVector<DcmSegment*> segments;
+
+    OFCondition result = DcmIODUtil::readSubSequence<OFVector<DcmSegment*> >(
+        item, DCM_SegmentSequence, segments, "1-n", "1", "SegmentationImageModule");
+    if (result.good())
+    {
+        for (size_t count = 0; count < segments.size(); count++)
+        {
+            if (result.good())
+            {
+                if (m_Segments.insert(OFMake_pair(segments[count]->getSegmentNumberRead(), segments[count])).second
+                    == false)
+                {
+                    DCMSEG_ERROR("Cannot insert segment " << segments[count]->getSegmentNumberRead()
+                                                          << " since it already exists");
+                    result = EC_IllegalCall;
+                    break;
+                }
+            }
+            else
+            {
+                DCMSEG_ERROR("Cannot read segment number for segment " << count << ": " << result.text());
+                result = EC_IllegalCall;
+                break;
+            }
+        }
+    }
+
+    return result;
 }
 
 OFCondition DcmSegmentation::readFrames(DcmItem& dataset)
@@ -839,61 +1140,88 @@ OFCondition DcmSegmentation::readFrames(DcmItem& dataset)
     DcmElement* pixelData = NULL;
     if (dataset.findAndGetElement(DCM_PixelData, pixelData).bad())
         return IOD_EC_InvalidPixelData;
-    if (!checkPixDataLength(pixelData, rows, cols, numberOfFrames))
+    Uint16 bytesPerPixel = (allocated >= 8) ? allocated / 8 : 1;
+    if (!checkPixDataLength(pixelData, rows, cols, bytesPerPixel, numberOfFrames))
         return IOD_EC_InvalidPixelData;
+    if (bytesPerPixel == 2)
+    {
+        m_16BitPixelData = OFTrue;
+    }
 
     /* Get pixel data values */
-    Uint8* pixels = NULL;
-    result        = pixelData->getUint8Array(pixels);
+    size_t pixelsPerFrame = OFstatic_cast(size_t, rows) * cols;
+    result                = readPixelData(pixelData, numberOfFrames, pixelsPerFrame, allocated);
+    return result;
+}
+
+OFCondition DcmSegmentation::readPixelData(DcmElement* pixelData, const size_t numFrames, const size_t pixelsPerFrame, const Uint16 bitsAlloc)
+{
+    Uint8*  pixels8    = NULL;
+    Uint16* pixels16   = NULL;
+    OFCondition result;
+    if (( bitsAlloc == 1) || (bitsAlloc == 8))
+    {
+        result = pixelData->getUint8Array(pixels8);
+    }
+    else if (bitsAlloc == 16)
+    {
+        result = pixelData->getUint16Array(pixels16);
+    }
+    else
+    {
+        DCMSEG_ERROR("Cannot read pixel data: Bits Allocated is neither 1, 8 nor 16");
+        return IOD_EC_InvalidPixelData;
+    }
     if (result.bad())
     {
         DCMSEG_ERROR("Cannot read pixel data");
         return result;
     }
-
     /* Read all frames into dedicated data structure */
-    size_t pixelsPerFrame = OFstatic_cast(size_t, rows) * cols;
-    if (m_SegmentationType == DcmSegTypes::ST_BINARY)
-    {
-        result = DcmIODUtil::extractBinaryFrames(pixels, numberOfFrames, pixelsPerFrame, m_Frames);
-        if (result.bad())
-        {
-            return result;
-        }
-        // with debug logging enabled, print out the binary frames
-        if (DCM_dcmsegLogger.isEnabledFor(dcmtk::log4cplus::DEBUG_LOG_LEVEL))
-        {
-            DCMSEG_DEBUG("Extracted binary segmentation frame:");
-            for (size_t count = 0; count < m_Frames.size(); count++)
-            {
-                DCMSEG_DEBUG("Frame " << count << ":");
-                DcmIODTypes::Frame* frame = m_Frames[count];
-                DcmSegUtils::debugDumpBin(frame->pixData, frame->length, "Binary frame", OFTrue);
-            }
-        }
-    }
-    else if (m_SegmentationType == DcmSegTypes::ST_FRACTIONAL)
+    switch (m_SegmentationType)
     {
-        for (size_t count = 0; count < numberOfFrames; count++)
-        {
-            DcmIODTypes::Frame* frame = new DcmIODTypes::Frame();
-            if (!frame)
-                return EC_MemoryExhausted;
-            frame->length  = pixelsPerFrame;
-            frame->pixData = new Uint8[pixelsPerFrame];
-            if (!frame->pixData)
+        case DcmSegTypes::ST_BINARY:
+            result = DcmIODUtil::extractBinaryFrames(pixels8, numFrames, pixelsPerFrame, m_Frames);
+            break;
+        case DcmSegTypes::ST_FRACTIONAL:
+        case DcmSegTypes::ST_LABELMAP:
+            for (size_t count = 0; count < numFrames; count++)
             {
-                delete frame;
-                return EC_MemoryExhausted;
+                DcmIODTypes::FrameBase* frame = NULL;
+                if (bitsAlloc == 8)
+                {
+                    frame = new DcmIODTypes::Frame<Uint8>(pixelsPerFrame);
+                }
+                else if (bitsAlloc == 16)
+                {
+                    frame = new DcmIODTypes::Frame<Uint16>(pixelsPerFrame);
+                }
+                if (!frame || !frame->getPixelData())
+                {
+                    delete frame;
+                    result = EC_MemoryExhausted;
+                    break;
+                }
+                if (bitsAlloc == 8)
+                {
+                    memcpy(frame->getPixelData(), pixels8 + count * pixelsPerFrame, pixelsPerFrame);
+                }
+                else // 16
+                {
+                    memcpy(frame->getPixelData(), pixels16 + count * pixelsPerFrame, frame->getLengthInBytes());
+                }
+                // print frame->pixData to cout
+                // frame->print();
+                m_Frames.push_back(frame);
             }
-            memcpy(frame->pixData, pixels + count * pixelsPerFrame, pixelsPerFrame);
-            m_Frames.push_back(frame);
-        }
+            break;
+        case DcmSegTypes::ST_UNKNOWN:
+            result = SG_EC_UnknownSegmentationType;
     }
-
     return result;
 }
 
+
 OFCondition DcmSegmentation::getAndCheckImagePixelAttributes(DcmItem& dataset,
                                                              Uint16& allocated,
                                                              Uint16& stored,
@@ -944,32 +1272,63 @@ OFCondition DcmSegmentation::getAndCheckImagePixelAttributes(DcmItem& dataset,
         }
     }
 
-    Uint16 depth = 0;
-    if (m_SegmentationType == DcmSegTypes::ST_BINARY)
-        depth = 1;
-    else
-        depth = 8;
-
-    if (allocated != depth)
+    switch (m_SegmentationType)
     {
-        DCMSEG_WARN("Bits Allocated is not set correctly ("
-                    << allocated << ", ignored), assuming value " << depth << " as required for "
-                    << DcmSegTypes::segtype2OFString(m_SegmentationType) << " segmentation objects");
-        allocated = depth;
+        case DcmSegTypes::ST_BINARY:
+            if (allocated != 1)
+            {
+                DCMSEG_WARN("Bits Allocated is not set correctly ("
+                            << allocated << ", ignored), assuming value 1 as required for binary segmentation objects");
+                allocated = 1;
+            }
+            break;
+        case DcmSegTypes::ST_FRACTIONAL:
+            if (allocated != 8)
+            {
+                DCMSEG_WARN("Bits Allocated is not set correctly ("
+                            << allocated
+                            << ", ignored), assuming value 8 as required for fractional segmentation "
+                               "objects");
+                allocated = 8;
+            }
+            break;
+        case DcmSegTypes::ST_LABELMAP:
+            if ((allocated != 8) && (allocated != 16))
+            {
+                DCMSEG_ERROR("Bits Allocated is not set correctly (" << allocated << ", giving up");
+                fail = OFTrue;
+            }
+            break;
+        case DcmSegTypes::ST_UNKNOWN:
+            fail = OFTrue;
+            break;
+    }
+    if (fail)
+    {
+        return EC_InvalidValue;
     }
-    if (stored != depth)
+    if (stored != allocated)
     {
         DCMSEG_WARN("Bits Stored is not set correctly ("
-                    << stored << ", ignored), assuming value " << depth << " as required for "
+                    << stored << ", ignored), assuming value " << allocated << " as required for "
                     << DcmSegTypes::segtype2OFString(m_SegmentationType) << " segmentation objects");
-        stored = depth;
+        stored = allocated;
+    }
+    if (m_SegmentationType == DcmSegTypes::ST_BINARY)
+    {
+        if (high != 0)
+        {
+            DCMSEG_WARN("High Bit is not set correctly ("
+                        << high << ", ignored), assuming value 0 as required for binary segmentation objects");
+            high = 0;
+        }
     }
-    if (high != depth - 1)
+    else if (high != allocated - 1)
     {
         DCMSEG_WARN("High Bit is not set correctly ("
-                    << high << ", ignored), assuming value " << depth - 1 << " as required for "
+                    << high << ", ignored), assuming value " << allocated - 1 << " as required for "
                     << DcmSegTypes::segtype2OFString(m_SegmentationType) << " segmentation objects");
-        high = depth - 1;
+        high = allocated - 1;
     }
     if (spp != 1)
     {
@@ -983,11 +1342,11 @@ OFCondition DcmSegmentation::getAndCheckImagePixelAttributes(DcmItem& dataset,
                     << pixelRep << ", ignored), assuming value 0 as required for segmentation objects");
         pixelRep = 0;
     }
-    if (colorModel != "MONOCHROME2")
+    if ((colorModel != "MONOCHROME2")
+        && ((colorModel != "PALETTE COLOR") && (m_SegmentationType == DcmSegTypes::ST_LABELMAP)))
     {
-        DCMSEG_WARN("Photometric Interpretation is not set correctly (ignored), assuming value MONOCHROME2 as required "
-                    "for segmentation objects");
-        colorModel = "MONOCHROME2";
+        DCMSEG_WARN("Photometric Interpretation is not set correctly (" << colorModel << "): Must be MONOCHROME2 or PALETTE COLOR (only Labelmap segmentations)");
+        fail = OFTrue;
     }
     if (rows == 0)
     {
@@ -1008,38 +1367,67 @@ OFCondition DcmSegmentation::getAndCheckImagePixelAttributes(DcmItem& dataset,
 
 OFCondition DcmSegmentation::writeDataset(DcmItem& dataset)
 {
-    Uint8* pixData = NULL;
-    size_t pixDataLength;
-    OFCondition result = writeWithSeparatePixelData(dataset, pixData, pixDataLength);
+    Uint8* pixData8 = NULL;
+    Uint16* pixData16 = NULL;
+    size_t pixDataLength = 0;
+    OFCondition result;
+    if (has16BitPixelData())
+    {
+        result = writeWithSeparatePixelData(dataset, pixData16, pixDataLength);
+    }
+    else
+    {
+       result = writeWithSeparatePixelData(dataset, pixData8, pixDataLength);
+    }
     if (result.good())
     {
         // Check whether pixel data length exceeds maximum number of bytes for uncompressed pixel data,
         // enforced by length field of Pixel Data attribute VR OB/OW if written in explicit VR transfer syntax.
         if (pixDataLength <= 4294967294UL)
         {
-            result
-                = dataset.putAndInsertUint8Array(DCM_PixelData, pixData, OFstatic_cast(unsigned long, pixDataLength));
+            if (has16BitPixelData())
+            {
+                result = dataset.putAndInsertUint16Array(DCM_PixelData, pixData16, OFstatic_cast(unsigned long, pixDataLength / 2));
+            }
+            else
+            {
+                result = dataset.putAndInsertUint8Array(DCM_PixelData, pixData8, OFstatic_cast(unsigned long, pixDataLength));
+            }
         }
         else
         {
             result = FG_EC_PixelDataTooLarge;
         }
-        delete[] pixData;
+        delete[] pixData8;
+        delete[] pixData16;
     }
     return result;
 }
 
 OFCondition DcmSegmentation::writeConcatenation(ConcatenationCreator& cc)
 {
-    Uint8* pixData       = NULL;
     size_t pixDataLength = 0;
     DcmItem* item        = new DcmItem();
     if (!item)
         return EC_MemoryExhausted;
-    OFCondition result = writeWithSeparatePixelData(*item, pixData, pixDataLength);
-    if (result.good())
+    OFCondition result;
+    if (has16BitPixelData())
+    {
+        Uint16* pixData = NULL;
+        result          = writeWithSeparatePixelData(*item, pixData, pixDataLength);
+        if (result.good())
+        {
+            result = cc.setCfgInput(item, pixData, pixDataLength, OFTrue /* transfer ownership */);
+        }
+    }
+    else
     {
-        result = cc.setCfgInput(item, pixData, pixDataLength, OFTrue /* transfer ownership */);
+        Uint8* pixData = NULL;
+        result         = writeWithSeparatePixelData(*item, pixData, pixDataLength);
+        if (result.good())
+        {
+            result = cc.setCfgInput(item, pixData, pixDataLength, OFTrue /* transfer ownership */);
+        }
     }
     return result;
 }
@@ -1060,13 +1448,15 @@ OFCondition DcmSegmentation::writeMultiFrameDimensionModule(DcmItem& dataset)
     return m_DimensionModule.write(dataset);
 }
 
-OFCondition DcmSegmentation::writeFractionalFrames(Uint8* pixData)
+template <typename T>
+OFCondition DcmSegmentation::writeByteBasedFrames(T* pixData)
 {
-    OFVector<DcmIODTypes::Frame*>::iterator it = m_Frames.begin();
+    Uint8 bytesPerPixel = sizeof(T);
+    typename OFVector<DcmIODTypes::FrameBase*>::iterator it = m_Frames.begin();
     // Just copy bytes for each frame as is
     for (size_t count = 0; it != m_Frames.end(); count++)
     {
-        memcpy(pixData + count * (*it)->length, (*it)->pixData, (*it)->length);
+        memcpy(pixData + count * (*it)->getLengthInBytes() / bytesPerPixel, (*it)->getPixelData(), (*it)->getLengthInBytes());
         it++;
     }
     return EC_Normal;
@@ -1084,13 +1474,17 @@ OFCondition DcmSegmentation::writeSegmentationImageModule(DcmItem& dataset)
     dataset.putAndInsertOFStringArray(DCM_ImageType, "DERIVED\\PRIMARY");
 
     OFCondition result = m_ContentIdentificationMacro.write(dataset);
+    OFString colorModel;
 
     /* Write hardcoded values */
     if (result.good())
-    {
-        getImagePixel().setSamplesPerPixel(1);
-        getImagePixel().setPhotometricInterpretation("MONOCHROME2");
-        getImagePixel().setPixelRepresentation(0);
+    {   Uint16 rows, cols, bitsAlloc, bitsStored, highBit, pixelRep, samplesPixel;
+        rows = cols = bitsAlloc = bitsStored = highBit = pixelRep = samplesPixel = 0;
+        OFString photometricInterpretation;
+        samplesPixel = 1;
+
+        colorModel = determineColorModel();
+        pixelRep = 0;
 
         /* Write Bits Allocated/Stored, High Bit, Segmentation Fractional Type,
          * Segmentation Type, Maximum Fractional Value
@@ -1099,29 +1493,45 @@ OFCondition DcmSegmentation::writeSegmentationImageModule(DcmItem& dataset)
         {
             case DcmSegTypes::ST_BINARY:
             {
-                getImagePixel().setBitsAllocated(1);
-                getImagePixel().setBitsStored(1);
-                getImagePixel().setHighBit(0);
+                bitsAlloc = 1;
+                bitsStored = 1;
+                highBit = 1;
                 dataset.putAndInsertOFStringArray(DCM_SegmentationType, "BINARY");
+                dataset.putAndInsertOFStringArray(DCM_SegmentsOverlap, "UNDEFINED");
                 break;
             }
             case DcmSegTypes::ST_FRACTIONAL:
+            case DcmSegTypes::ST_LABELMAP:
             {
-                getImagePixel().setBitsAllocated(8);
-                getImagePixel().setBitsStored(8);
-                getImagePixel().setHighBit(7);
-                dataset.putAndInsertOFStringArray(DCM_SegmentationType, "FRACTIONAL");
-                if (m_SegmentationFractionalType == DcmSegTypes::SFT_OCCUPANCY)
+                Uint8 numBits = 8;
+                if (has16BitPixelData())
                 {
-                    dataset.putAndInsertOFStringArray(DCM_SegmentationFractionalType, "OCCUPANCY");
+                    numBits = 16;
+                }
+                bitsAlloc = bitsStored = numBits;
+                highBit = numBits -1;
+
+                if (m_SegmentationType == DcmSegTypes::ST_LABELMAP)
+                {
+                    dataset.putAndInsertOFStringArray(DCM_SegmentationType, "LABELMAP");
+                    dataset.putAndInsertOFStringArray(DCM_SegmentsOverlap, "NO");
                 }
                 else
                 {
-                    dataset.putAndInsertOFStringArray(DCM_SegmentationFractionalType, "PROBABILITY");
+                    dataset.putAndInsertOFStringArray(DCM_SegmentationType, "FRACTIONAL");
+                    dataset.putAndInsertOFStringArray(DCM_SegmentsOverlap, "UNDEFINED");
+                    if (m_SegmentationFractionalType == DcmSegTypes::SFT_OCCUPANCY)
+                    {
+                        dataset.putAndInsertOFStringArray(DCM_SegmentationFractionalType, "OCCUPANCY");
+                    }
+                    else
+                    {
+                        dataset.putAndInsertOFStringArray(DCM_SegmentationFractionalType, "PROBABILITY");
+                    }
+                    // Maximum Fractional Value: Attribute is type 1C but "required if .. FRACTIONAL", i.e. write type 1
+                    DcmIODUtil::copyElementToDataset(
+                        result, dataset, m_MaximumFractionalValue, "1", "1", "SegmentationImageModule");
                 }
-                // Maximum Fractional Value: Attribute is type 1C but "required if .. FRACTIONAL", i.e. write type 1
-                DcmIODUtil::copyElementToDataset(
-                    result, dataset, m_MaximumFractionalValue, "1", "1", "SegmentationImageModule");
                 break;
             }
             case DcmSegTypes::ST_UNKNOWN:
@@ -1131,13 +1541,26 @@ OFCondition DcmSegmentation::writeSegmentationImageModule(DcmItem& dataset)
                 break;
             }
         }
+        getImagePixel().getRows(rows);
+        getImagePixel().getColumns(cols);
+        if (bitsAlloc == 16)
+        {
+            result = SetImagePixelModuleVisitor(rows, cols,bitsAlloc, bitsStored, highBit, samplesPixel, colorModel)
+            (*OFget<IODImagePixelModule<Uint16> >(&getImagePixel()));
+        }
+        else
+        {
+            result = SetImagePixelModuleVisitor(rows, cols,bitsAlloc, bitsStored, highBit, samplesPixel, colorModel)
+            (*OFget<IODImagePixelModule<Uint8> >(&getImagePixel()));
+        }
+
     }
 
     /* Write segments */
     OFVector<DcmItem*> segmentItems;
     if (result.good())
     {
-        OFVector<DcmSegment*>::iterator it = m_Segments.begin();
+        OFMap<Uint16, DcmSegment*>::iterator it = m_Segments.begin();
         dataset.findAndDeleteElement(DCM_SegmentSequence);
         for (Uint16 itemCount = 0; (it != m_Segments.end()) && result.good(); itemCount++)
         {
@@ -1145,11 +1568,11 @@ OFCondition DcmSegmentation::writeSegmentationImageModule(DcmItem& dataset)
             dataset.findOrCreateSequenceItem(DCM_SegmentSequence, segmentItem, itemCount);
             if (segmentItem)
             {
-                result = (*it)->write(*segmentItem);
+                result = (*it).second->write(*segmentItem);
                 /* Insert segment number for the segment, starting from 1 and increasing monotonically. */
                 if (result.good())
                 {
-                    segmentItem->putAndInsertUint16(DCM_SegmentNumber, itemCount + 1);
+                    segmentItem->putAndInsertUint16(DCM_SegmentNumber, (*it).first);
                 }
             }
             else
@@ -1172,7 +1595,7 @@ void DcmSegmentation::clearData()
     m_FG.clearData();
     m_FGInterface.clear();
     DcmIODUtil::freeContainer(m_Frames);
-    DcmIODUtil::freeContainer(m_Segments);
+    DcmIODUtil::freeMap(m_Segments);
     m_MaximumFractionalValue.clear();
     m_SegmentationFractionalType = DcmSegTypes::SFT_UNKNOWN;
     m_SegmentationType           = DcmSegTypes::ST_UNKNOWN;
@@ -1181,6 +1604,7 @@ void DcmSegmentation::clearData()
 OFBool DcmSegmentation::checkPixDataLength(DcmElement* pixelData,
                                            const Uint16 rows,
                                            const Uint16 cols,
+                                           const Uint16 bytesPerPixel,
                                            const Uint32& numberOfFrames)
 {
     // Get actual length of pixel data in bytes
@@ -1188,7 +1612,7 @@ OFBool DcmSegmentation::checkPixDataLength(DcmElement* pixelData,
 
     // Find out how many bytes are needed
     size_t bytesRequired = 0;
-    OFCondition result   = getTotalBytesRequired(rows, cols, numberOfFrames, bytesRequired);
+    OFCondition result   = getTotalBytesRequired(rows, cols, bytesPerPixel, numberOfFrames, bytesRequired);
     if (result.bad())
         return OFFalse;
     // Length found in Pixel Data element is always even
@@ -1216,19 +1640,27 @@ OFBool DcmSegmentation::checkPixDataLength(DcmElement* pixelData,
 
 OFCondition DcmSegmentation::getTotalBytesRequired(const Uint16& rows,
                                                    const Uint16& cols,
+                                                   const Uint16& bytesPerPixel,
                                                    const Uint32& numberOfFrames,
                                                    size_t& bytesRequired)
 {
+    // Compute space needed for all frames, first assume 1 byte per pixel (we adapt later for binary segmentations)
+    // Rows * Cols = num pixels per frame
     OFBool ok = OFStandard::safeMult(OFstatic_cast(size_t, rows), OFstatic_cast(size_t, cols), bytesRequired);
+    // Pixels per frame * num frames = total num pixels
     if (ok)
         OFStandard::safeMult(bytesRequired, OFstatic_cast(size_t, numberOfFrames), bytesRequired);
+    // In case of 16 bit pixel data, we need twice as much space
+    if (ok && (bytesPerPixel == 2))
+        OFStandard::safeMult(bytesRequired, OFstatic_cast(size_t, 2), bytesRequired);
     if (!ok)
     {
         DCMSEG_ERROR("Cannot compute number of bytes required for Pixel Data since size_t type is too small");
         return EC_TooManyBytesRequested;
     }
 
-    /* for binary, we only need one bit per pixel */
+    // Until this point we assumed bytes per pixel = 1. Now we need to adjust this
+    // for binary segmentation objects.with 1 bit per pixel.
     size_t remainder = 0;
     if (m_SegmentationType == DcmSegTypes::ST_BINARY)
     {
@@ -1245,10 +1677,10 @@ OFCondition DcmSegmentation::getTotalBytesRequired(const Uint16& rows,
     return EC_Normal;
 }
 
-OFCondition DcmSegmentation::loadFile(DcmFileFormat& dcmff, const OFString& filename, DcmDataset*& dset)
+OFCondition DcmSegmentation::loadFile(DcmFileFormat& dcmff, const OFString& filename, DcmDataset*& dset, const E_TransferSyntax xfer)
 {
     dset               = NULL;
-    OFCondition result = dcmff.loadFile(filename.c_str());
+    OFCondition result = dcmff.loadFile(filename.c_str(), xfer);
     if (result.bad())
     {
         DCMSEG_ERROR("Could not load file " << filename << ": " << result.text());
@@ -1263,6 +1695,7 @@ OFCondition DcmSegmentation::loadFile(DcmFileFormat& dcmff, const OFString& file
     return result;
 }
 
+
 OFCondition DcmSegmentation::readSegmentationFractionalType(DcmItem& item)
 {
     m_SegmentationFractionalType = DcmSegTypes::SFT_UNKNOWN;
@@ -1272,7 +1705,7 @@ OFCondition DcmSegmentation::readSegmentationFractionalType(DcmItem& item)
     }
     DcmCodeString element(DCM_SegmentationFractionalType);
     OFCondition result = DcmIODUtil::getAndCheckElementFromDataset(
-        item, element, getRules()->getByTag(DCM_SegmentationFractionalType));
+        item, element, DcmSegmentation::IODImage::getRules()->getByTag(DCM_SegmentationFractionalType));
     OFString str;
     if (result.good())
     {
@@ -1298,8 +1731,8 @@ OFCondition DcmSegmentation::readSegmentationType(DcmItem& item)
     }
 
     DcmCodeString element(DCM_SegmentationType);
-    OFCondition result
-        = DcmIODUtil::getAndCheckElementFromDataset(item, element, getRules()->getByTag(DCM_SegmentationType));
+    OFCondition result = DcmIODUtil::getAndCheckElementFromDataset(
+        item, element, DcmSegmentation::IODImage::getRules()->getByTag(DCM_SegmentationType));
     OFString str;
     if (result.good())
     {
@@ -1316,11 +1749,6 @@ OFCondition DcmSegmentation::readSegmentationType(DcmItem& item)
     return result;
 }
 
-// protected override of public base class function
-IODImagePixelModule<Uint8>& DcmSegmentation::getImagePixel()
-{
-    return *OFget<IODImagePixelModule<Uint8> >(&DcmSegmentation::IODImage::getImagePixel());
-}
 
 OFBool DcmSegmentation::check(const OFBool checkFGStructure)
 {
@@ -1339,7 +1767,10 @@ OFBool DcmSegmentation::check(const OFBool checkFGStructure)
         DCMSEG_ERROR("Too many segments defined");
         return OFFalse;
     }
-    if (m_Segments.size() > m_Frames.size())
+    // Check that all segments are referenced by at least one frame.
+    // This is not required for label maps, since frames are only indirectly (through their pixel values)
+    // referencing segments.
+    if ( (m_Segments.size() > m_Frames.size()) && (m_SegmentationType != DcmSegTypes::ST_LABELMAP) )
     {
         DCMSEG_ERROR("More segments than frames defined");
         return OFFalse;
@@ -1367,7 +1798,7 @@ OFBool DcmSegmentation::check(const OFBool checkFGStructure)
         frameOfRefRequired = OFFalse;
     }
     OFString frameOfRef;
-    getFrameOfReference().getFrameOfReferenceUID(frameOfRef);
+    DcmSegmentation::IODImage::getFrameOfReference().getFrameOfReferenceUID(frameOfRef);
     if (frameOfRefRequired && frameOfRef.empty())
     {
         DCMSEG_ERROR("Frame of Reference UID is not set for Segmentation but is required");
@@ -1443,3 +1874,78 @@ OFCondition DcmSegmentation::decompress(DcmDataset& dset)
     return result;
 }
 
+
+OFString DcmSegmentation::determineColorModel()
+{
+    OFString colorModel;
+    if (m_SegmentationType == DcmSegTypes::ST_LABELMAP)
+    {
+        colorModel = DcmSegTypes::labelmapColorModel2OFString(m_LabelmapColorModel, "MONOCHROME2");
+    }
+    else
+    {
+        colorModel = "MONOCHROME2";
+    }
+    return colorModel;
+}
+
+
+OFBool DcmSegmentation::checkColorModel(const OFString& photometricInterpretation)
+{
+    // For labelmaps, MONOCHROME2 and PALETTE is permitted
+    if (m_SegmentationType == DcmSegTypes::ST_LABELMAP)
+    {
+        if ((photometricInterpretation != "MONOCHROME2") && (photometricInterpretation != "PALETTE COLOR"))
+        {
+            DCMSEG_WARN("Photometric Interpretation is not set correctly (" << photometricInterpretation << "): Must be MONOCHROME2 or PALETTE COLOR for labelmaps");
+            m_LabelmapColorModel = DcmSegTypes::SLCM_UNKNOWN;
+            return OFFalse;
+        }
+        m_LabelmapColorModel = DcmSegTypes::OFString2LabelmapColorModel(photometricInterpretation);
+    }
+    else
+    {
+        if (photometricInterpretation != "MONOCHROME2")
+        {
+            DCMSEG_WARN("Photometric Interpretation is not set correctly (" << photometricInterpretation << "): Must be MONOCHROME2 for binary and fractional segmentations");
+            return OFFalse;
+        }
+        m_LabelmapColorModel = DcmSegTypes::SLCM_UNKNOWN; // not used for binary/fractional segmentations
+    }
+    // If we found PALETTE COLOR, check whether the Palette Color Lookup Table is present
+    if (m_LabelmapColorModel == DcmSegTypes::SLCM_PALETTE)
+    {
+        if (getPaletteColorLUT().numBits() == 0) // checks at least basic descriptor availability
+        {
+            DCMSEG_WARN("Photometric Interpretation is set to PALETTE COLOR but no or invalid Palette Color Lookup Table is present");
+            return OFFalse;
+        }
+    }
+    return OFTrue;
+}
+
+
+void DcmSegmentation::setSOPClassUIDBasedOnSegmentationType()
+{
+   switch (m_SegmentationType)
+    {
+        case DcmSegTypes::ST_LABELMAP:
+            DcmSegmentation::IODImage::getSOPCommon().setSOPClassUID(UID_LabelMapSegmentationStorage);
+            break;
+        case DcmSegTypes::ST_FRACTIONAL:
+        case DcmSegTypes::ST_BINARY:
+            DcmSegmentation::IODImage::getSOPCommon().setSOPClassUID(UID_SegmentationStorage);
+            break;
+        case DcmSegTypes::ST_UNKNOWN:
+            // Print warning if segmentation type is unknown
+            DCMSEG_WARN("Segmentation type is unknown, setting SOP Class UID to Segmentation Storage SOP Class");
+            DcmSegmentation::IODImage::getSOPCommon().setSOPClassUID(UID_SegmentationStorage);
+            break;
+    }
+}
+
+// Explicit instantiations
+template OFCondition DcmSegmentation::addFrame<Uint8>(Uint8*, const Uint16, const OFVector<FGBase*>&);
+template OFCondition DcmSegmentation::addFrame<Uint16>(Uint16*, const Uint16, const OFVector<FGBase*>&);
+template OFCondition DcmSegmentation::addFrame<Uint8>(Uint8* pixData);
+template OFCondition DcmSegmentation::addFrame<Uint16>(Uint16* pixData);
index f7741487693bfabc4f157b1cb11db986b89961ce..0b54774549c6f98d3bd48c408871bc07dbcb8777 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 
 #include "dcmtk/config/osconfig.h"
 
+#include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmiod/iodutil.h"
 #include "dcmtk/dcmseg/segdoc.h"
 #include "dcmtk/dcmseg/segment.h"
 #include "dcmtk/dcmseg/segtypes.h"
+#include "dcmtk/ofstd/oftypes.h"
 
 OFCondition DcmSegment::create(DcmSegment*& segment,
                                const OFString& segmentLabel,
@@ -66,13 +68,59 @@ OFCondition DcmSegment::create(DcmSegment*& segment,
     return result;
 }
 
+
+
+DcmSegment* DcmSegment::clone(DcmSegmentation* seg)
+{
+    DcmSegment* newSegment = new DcmSegment(*this);
+    if (newSegment != NULL)
+    {
+        if (seg != NULL)
+            newSegment->m_SegmentationDoc = seg;
+        // else: keep reference to same DcmSegmentation document
+    }
+    return newSegment;
+}
+
+DcmSegment::DcmSegment(const DcmSegment& rhs)
+    : m_SegmentationDoc(rhs.m_SegmentationDoc)
+    , m_SegmentNumber(rhs.m_SegmentNumber)
+    , m_SegmentDescription(rhs.m_SegmentDescription)
+    , m_SegmentAlgorithmName(rhs.m_SegmentAlgorithmName)
+    , m_SegmentationAlgorithmIdentification(rhs.m_SegmentationAlgorithmIdentification)
+    , m_RecommendedDisplayGrayscaleValue(rhs.m_RecommendedDisplayGrayscaleValue)
+    , m_RecommendedDisplayCIELabValue(rhs.m_RecommendedDisplayCIELabValue)
+    , m_TrackingID(rhs.m_TrackingID)
+    , m_TrackingUID(rhs.m_TrackingUID)
+    , m_Rules(rhs.m_Rules->clone())
+{
+}
+
+DcmSegment& DcmSegment::operator=(const DcmSegment& rhs)
+{
+    if (this != &rhs)
+    {
+        m_SegmentationDoc                        = rhs.m_SegmentationDoc;
+        m_SegmentNumber                          = rhs.m_SegmentNumber;
+        m_SegmentDescription                     = rhs.m_SegmentDescription;
+        m_SegmentAlgorithmName                   = rhs.m_SegmentAlgorithmName;
+        m_SegmentationAlgorithmIdentification    = rhs.m_SegmentationAlgorithmIdentification;
+        m_RecommendedDisplayGrayscaleValue       = rhs.m_RecommendedDisplayGrayscaleValue;
+        m_RecommendedDisplayCIELabValue          = rhs.m_RecommendedDisplayCIELabValue;
+        m_TrackingID                             = rhs.m_TrackingID;
+        m_TrackingUID                            = rhs.m_TrackingUID;
+        m_Rules.reset(rhs.m_Rules->clone());
+    }
+    return *this;
+}
+
 OFCondition DcmSegment::read(DcmItem& item, const OFBool clearOldData)
 {
     if (clearOldData)
         clearData();
 
     m_SegmentDescription.read(item);
-    DcmIODUtil::getAndCheckElementFromDataset(item, m_SegmentAlgorithmName, m_Rules.getByTag(DCM_SegmentAlgorithmName));
+    DcmIODUtil::getAndCheckElementFromDataset(item, m_SegmentAlgorithmName, m_Rules->getByTag(DCM_SegmentAlgorithmName));
 
     DcmIODUtil::readSingleItem<AlgorithmIdentificationMacro>(item,
                                                              DCM_SegmentationAlgorithmIdentificationSequence,
@@ -81,11 +129,12 @@ OFCondition DcmSegment::read(DcmItem& item, const OFBool clearOldData)
                                                              "Segmentation Image Module");
 
     DcmIODUtil::getAndCheckElementFromDataset(
-        item, m_RecommendedDisplayGrayscaleValue, m_Rules.getByTag(DCM_RecommendedDisplayGrayscaleValue));
+        item, m_RecommendedDisplayGrayscaleValue, m_Rules->getByTag(DCM_RecommendedDisplayGrayscaleValue));
     DcmIODUtil::getAndCheckElementFromDataset(
-        item, m_RecommendedDisplayCIELabValue, m_Rules.getByTag(DCM_RecommendedDisplayCIELabValue));
-    DcmIODUtil::getAndCheckElementFromDataset(item, m_TrackingID, m_Rules.getByTag(DCM_TrackingID));
-    DcmIODUtil::getAndCheckElementFromDataset(item, m_TrackingUID, m_Rules.getByTag(DCM_TrackingUID));
+        item, m_RecommendedDisplayCIELabValue, m_Rules->getByTag(DCM_RecommendedDisplayCIELabValue));
+    DcmIODUtil::getAndCheckElementFromDataset(item, m_TrackingID, m_Rules->getByTag(DCM_TrackingID));
+    DcmIODUtil::getAndCheckElementFromDataset(item, m_TrackingUID, m_Rules->getByTag(DCM_TrackingUID));
+    DcmIODUtil::getAndCheckElementFromDataset(item, m_SegmentNumber, m_Rules->getByTag(DCM_SegmentNumber));
 
     return EC_Normal;
 }
@@ -94,7 +143,7 @@ OFCondition DcmSegment::write(DcmItem& item)
 {
     OFCondition result;
     result = m_SegmentDescription.write(item);
-    DcmIODUtil::copyElementToDataset(result, item, m_SegmentAlgorithmName, m_Rules.getByTag(DCM_SegmentAlgorithmName));
+    DcmIODUtil::copyElementToDataset(result, item, m_SegmentAlgorithmName, m_Rules->getByTag(DCM_SegmentAlgorithmName));
 
     if (result.good() && m_SegmentationAlgorithmIdentification.check(OFTrue /* quiet */).good())
     {
@@ -107,17 +156,20 @@ OFCondition DcmSegment::write(DcmItem& item)
     }
 
     DcmIODUtil::copyElementToDataset(
-        result, item, m_RecommendedDisplayGrayscaleValue, m_Rules.getByTag(DCM_RecommendedDisplayGrayscaleValue));
+        result, item, m_RecommendedDisplayGrayscaleValue, m_Rules->getByTag(DCM_RecommendedDisplayGrayscaleValue));
     DcmIODUtil::copyElementToDataset(
-        result, item, m_RecommendedDisplayCIELabValue, m_Rules.getByTag(DCM_RecommendedDisplayCIELabValue));
-    DcmIODUtil::copyElementToDataset(result, item, m_TrackingID, m_Rules.getByTag(DCM_TrackingID));
-    DcmIODUtil::copyElementToDataset(result, item, m_TrackingUID, m_Rules.getByTag(DCM_TrackingUID));
+        result, item, m_RecommendedDisplayCIELabValue, m_Rules->getByTag(DCM_RecommendedDisplayCIELabValue));
+    DcmIODUtil::copyElementToDataset(result, item, m_TrackingID, m_Rules->getByTag(DCM_TrackingID));
+    DcmIODUtil::copyElementToDataset(result, item, m_TrackingUID, m_Rules->getByTag(DCM_TrackingUID));
+    m_SegmentNumber.putUint16(getSegmentNumber());
+    DcmIODUtil::copyElementToDataset(result, item, m_SegmentNumber, m_Rules->getByTag(DCM_SegmentNumber));
 
     return result;
 }
 
 void DcmSegment::clearData()
 {
+    m_SegmentNumber.clear();
     m_SegmentDescription.clearData();
     m_SegmentAlgorithmName.clear();
     m_SegmentationAlgorithmIdentification.clearData();
@@ -133,8 +185,10 @@ DcmSegment::~DcmSegment()
 }
 
 // protected default constructor
+
 DcmSegment::DcmSegment()
     : m_SegmentationDoc(NULL)
+    , m_SegmentNumber(DCM_SegmentNumber)
     , m_SegmentDescription()
     , m_SegmentAlgorithmName(DCM_SegmentAlgorithmName)
     , m_SegmentationAlgorithmIdentification()
@@ -142,23 +196,25 @@ DcmSegment::DcmSegment()
     , m_RecommendedDisplayCIELabValue(DCM_RecommendedDisplayCIELabValue)
     , m_TrackingID(DCM_TrackingID)
     , m_TrackingUID(DCM_TrackingUID)
-    , m_Rules()
+    , m_Rules(new IODRules())
 {
     initIODRules();
 }
 
 void DcmSegment::initIODRules()
 {
-    m_Rules.addRule(new IODRule(DCM_SegmentAlgorithmName, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
+    m_Rules->addRule(new IODRule(DCM_SegmentNumber, "1", "1", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
                     OFTrue);
-    m_Rules.addRule(
+    m_Rules->addRule(new IODRule(DCM_SegmentAlgorithmName, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
+                    OFTrue);
+    m_Rules->addRule(
         new IODRule(DCM_RecommendedDisplayGrayscaleValue, "1", "3", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
         OFTrue);
-    m_Rules.addRule(
+    m_Rules->addRule(
         new IODRule(DCM_RecommendedDisplayCIELabValue, "3", "3", "SegmentationImageModule", DcmIODTypes::IE_IMAGE),
         OFTrue);
-    m_Rules.addRule(new IODRule(DCM_TrackingID, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
-    m_Rules.addRule(new IODRule(DCM_TrackingUID, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    m_Rules->addRule(new IODRule(DCM_TrackingID, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
+    m_Rules->addRule(new IODRule(DCM_TrackingUID, "1", "1C", "SegmentationImageModule", DcmIODTypes::IE_IMAGE), OFTrue);
 }
 
 // -------------- getters --------------------
@@ -254,6 +310,25 @@ OFCondition DcmSegment::getTrackingUID(OFString& value, const signed long pos)
     return DcmIODUtil::getStringValueFromElement(m_TrackingUID, value, pos);
 }
 
+Uint16 DcmSegment::getSegmentNumberRead()
+{
+    OFVector<Uint16> values;
+    DcmIODUtil::getUint16ValuesFromElement(m_SegmentNumber, values);
+    if (values.size() >0 )
+    {
+        return values[0];
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+OFshared_ptr<IODRules> DcmSegment::getIODRules()
+{
+    return m_Rules;
+}
+
 // -------------- setters --------------------
 
 OFCondition DcmSegment::setSegmentLabel(const OFString& value, const OFBool checkValue)
index 60adc7987db9c72e40c82cec0a009e724397aaaa..059c8df038e45dcf4b6bcceced7b6efb258abc6d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -39,6 +39,15 @@ makeOFConditionConst(SG_EC_UnknownSegmentationType, OFM_dcmseg, 3, OF_error, "Un
 makeOFConditionConst(SG_EC_InvalidValue, OFM_dcmseg, 4, OF_error, "Invalid value for Segmentation SOP Class");
 makeOFConditionConst(SG_EC_NotEnoughData, OFM_dcmseg, 5, OF_error, "Not enough data");
 makeOFConditionConst(SG_EC_MaxFramesReached, OFM_dcmseg, 6, OF_error, "Maximum Number of Frames reached");
+makeOFConditionConst(SG_EC_InvalidBitDepth, OFM_dcmseg, 7, OF_error, "Invalid bit depth for given Segmentation Type");
+makeOFConditionConst(SG_EC_FramesNotParallel, OFM_dcmseg, 8, OF_error, "Frames are not parallel");
+makeOFConditionConst(SG_EC_NoSegmentationBasedSOPClass, OFM_dcmseg, 9, OF_error, "No segmentation SOP class (Segmentation or Label Map Segmentation SOP Class)");
+makeOFConditionConst(SG_EC_NoConversionRequired, OFM_dcmseg, 10, OF_ok, "Segmentation-based object does not require requested conversion");
+makeOFConditionConst(SG_EC_AlreadyLabelMap, OFM_dcmseg, 11, OF_error, "Segmentation-based object is already a label map");
+makeOFConditionConst(SG_EC_CannotConvertFractionalToLabelmap, OFM_dcmseg, 12, OF_error, "Cannot convert fractional to label map segmentations");
+makeOFConditionConst(SG_EC_OverlappingSegments, OFM_dcmseg, 13, OF_error, "Binary segmentation contains overlapping segments");
+makeOFConditionConst(SG_EC_CannotConvertMissingCIELab, OFM_dcmseg, 14, OF_error, "Cannot convert to PALETTE color model since not all segments contain Recommended Display CIELab Value Macro");
+makeOFConditionConst(SG_EC_MissingPlanePositionPatient, OFM_dcmseg, 15, OF_error, "Missing Plane Position (Patient) Functional Group");
 
 DcmSegTypes::E_SegmentationType DcmSegTypes::OFString2Segtype(const OFString& value)
 {
@@ -46,6 +55,8 @@ DcmSegTypes::E_SegmentationType DcmSegTypes::OFString2Segtype(const OFString& va
         return DcmSegTypes::ST_BINARY;
     if (value == "FRACTIONAL")
         return DcmSegTypes::ST_FRACTIONAL;
+    if (value == "LABELMAP")
+        return DcmSegTypes::ST_LABELMAP;
     else
         return DcmSegTypes::ST_UNKNOWN;
 }
@@ -58,6 +69,8 @@ OFString DcmSegTypes::segtype2OFString(const DcmSegTypes::E_SegmentationType& va
             return "BINARY";
         case DcmSegTypes::ST_FRACTIONAL:
             return "FRACTIONAL";
+        case DcmSegTypes::ST_LABELMAP:
+            return "LABELMAP";
         case DcmSegTypes::ST_UNKNOWN:
             return "UNKNOWN";
         default:
@@ -105,6 +118,40 @@ DcmSegTypes::E_SegmentAlgoType DcmSegTypes::OFString2AlgoType(const OFString& al
         return DcmSegTypes::SAT_UNKNOWN;
 }
 
+
+OFString DcmSegTypes::labelmapColorModel2OFString(const DcmSegTypes::E_SegmentationLabelmapColorModel value, const OFString& fallbackValue)
+{
+    OFString result;
+    switch (value)
+    {
+        case DcmSegTypes::SLCM_MONOCHROME2:
+            return "MONOCHROME2";
+        case DcmSegTypes::SLCM_PALETTE:
+            return "PALETTE COLOR";
+        case DcmSegTypes::SLCM_UNKNOWN:
+            result = "UNKNOWN";
+        default:
+            result = "Invalid labelmap color model (internal error)";
+    }
+    if (!fallbackValue.empty())
+    {
+        DCMSEG_WARN("Invalid value for label map color model: " << result << ". Using fallback value: " << fallbackValue);
+        result = fallbackValue;
+    }
+    return result;
+}
+
+
+DcmSegTypes::E_SegmentationLabelmapColorModel DcmSegTypes::OFString2LabelmapColorModel(const OFString& value)
+{
+    if (value == "MONOCHROME2")
+        return DcmSegTypes::SLCM_MONOCHROME2;
+    if (value == "PALETTE COLOR")
+        return DcmSegTypes::SLCM_PALETTE;
+    else
+        return DcmSegTypes::SLCM_UNKNOWN;
+}
+
 SegmentDescriptionMacro::SegmentDescriptionMacro()
     : m_SegmentLabel(DCM_SegmentLabel)
     , m_SegmentDescription(DCM_SegmentDescription)
@@ -119,6 +166,27 @@ SegmentDescriptionMacro::~SegmentDescriptionMacro()
 {
 }
 
+SegmentDescriptionMacro& SegmentDescriptionMacro::operator=(const SegmentDescriptionMacro& rhs)
+{
+    if (this != &rhs)
+    {
+        m_SegmentLabel = rhs.m_SegmentLabel;
+        m_SegmentDescription = rhs.m_SegmentDescription;
+        m_SegmentAlgorithmType = rhs.m_SegmentAlgorithmType;
+        m_GeneralAnatomyCode = rhs.m_GeneralAnatomyCode;
+        m_SegmentedPropertyCategoryCode = rhs.m_SegmentedPropertyCategoryCode;
+        m_SegmentedPropertyType = rhs.m_SegmentedPropertyType;
+    }
+    return *this;
+}
+
+
+SegmentDescriptionMacro* SegmentDescriptionMacro::clone()
+{
+    return new SegmentDescriptionMacro(*this);
+}
+
+
 void SegmentDescriptionMacro::clearData()
 {
     m_SegmentLabel.clear();
@@ -270,6 +338,28 @@ SegmentedPropertyTypeCodeItem::SegmentedPropertyTypeCodeItem()
 {
 }
 
+SegmentedPropertyTypeCodeItem& SegmentedPropertyTypeCodeItem::operator=(const SegmentedPropertyTypeCodeItem& rhs)
+{
+    if (this != &rhs)
+    {
+        m_SegmentedPropertyTypeCode = rhs.m_SegmentedPropertyTypeCode;
+        DcmIODUtil::copyContainer(rhs.m_SegmentedPropertyTypeModifierCode, m_SegmentedPropertyTypeModifierCode);
+    }
+    return *this;
+}
+
+SegmentedPropertyTypeCodeItem* SegmentedPropertyTypeCodeItem::clone()
+{
+    return new SegmentedPropertyTypeCodeItem(*this);
+}
+
+SegmentedPropertyTypeCodeItem::SegmentedPropertyTypeCodeItem(const SegmentedPropertyTypeCodeItem& rhs)
+    : m_SegmentedPropertyTypeCode(rhs.m_SegmentedPropertyTypeCode)
+    , m_SegmentedPropertyTypeModifierCode()
+{
+    DcmIODUtil::copyContainer(rhs.m_SegmentedPropertyTypeModifierCode, m_SegmentedPropertyTypeModifierCode);
+}
+
 SegmentedPropertyTypeCodeItem::~SegmentedPropertyTypeCodeItem()
 {
     DcmIODUtil::freeContainer(m_SegmentedPropertyTypeModifierCode);
index 3b8b54628edf4fac50434480430aa386f432427e..6fa25a9fba2a4eda30d65947d55e4c601efa7894 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, Open Connections GmbH
+ *  Copyright (C) 2015-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 
 #include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/dcmseg/segtypes.h"
+#include <iostream>
 #include "dcmtk/dcmseg/segutils.h"
 
 
-DcmIODTypes::Frame* DcmSegUtils::packBinaryFrame(const Uint8* pixelData, const Uint16 rows, const Uint16 columns)
-{
-    // Sanity checking
-    const size_t totalBits = OFstatic_cast(size_t, rows) * columns;
-    if (totalBits == 0)
-    {
-        DCMSEG_ERROR("Unable to pack binary segmentation frame: Rows or Columns is 0");
-        return NULL;
-    }
-    if (!pixelData)
-    {
-        DCMSEG_ERROR("Unable to pack binary segmentation frame: No pixel data provided");
-        return NULL;
-    }
-
-    // Calculate total number of bytes required
-    size_t totalBytes = (totalBits + 7) / 8; // +7 to round up to the nearest byte
-
-    // Allocate memory for the packed bit array
-    Uint8* packedData = new Uint8[totalBytes];
-    if (packedData == NULL)
-    {
-        DCMSEG_ERROR("Cannot allocate memory for packed binary frame");
-        return NULL;
-    }
-    memset(packedData, 0, totalBytes); // Initialize to 0
-
-    // Pack the bits
-    for (Uint32 i = 0; i < totalBits; ++i) {
-        if (pixelData[i] != 0) {
-            Uint32 byteIndex = i / 8;
-            Uint32 bitIndex = i % 8;
-            DCMSEG_TRACE("bitIndex: " << bitIndex << ", byteIndex: " << byteIndex << ", packedData[byteIndex]: " << DcmSegUtils::debugByte2Bin(packedData[byteIndex]));
-            packedData[byteIndex] |= (1 << bitIndex); // Fill from right to left
-        }
-    }
-
-    // Create and return the frame
-    DcmIODTypes::Frame* frame = new DcmIODTypes::Frame();
-    if (frame == NULL)
-    {
-        DCMSEG_ERROR("Cannot allocate memory for packed binary frame");
-        delete[] packedData;
-        return NULL;
-    }
-    frame->pixData = packedData;
-    frame->length = totalBytes;
-    return frame;
-}
-
-OFCondition DcmSegUtils::concatBinaryFrames(const OFVector<DcmIODTypes::Frame*>& frames,
+OFCondition DcmSegUtils::concatBinaryFrames(const OFVector<DcmIODTypes::FrameBase*>& frames,
                                             const Uint16 rows,
                                             const Uint16 cols,
                                             Uint8* pixData,
@@ -99,25 +50,47 @@ OFCondition DcmSegUtils::concatBinaryFrames(const OFVector<DcmIODTypes::Frame*>&
     }
 
     // Initialize the target pixData array to 0
-    std::memset(pixData, 0, pixDataLength);
+    memset(pixData, 0, pixDataLength);
 
     // Concatenate the bits
-    Uint32 bitIndex = 0;
+    size_t bitIndex = 0;
+
     for (size_t frameIndex = 0; frameIndex < frames.size(); ++frameIndex)
     {
-        const DcmIODTypes::Frame* frame = frames[frameIndex];
-        Uint32 frameBits = rows * cols;
-        for (Uint32 i = 0; i < frameBits; ++i)
+        // Make sure frame has correct bit depth
+        if (frames[frameIndex]->bytesPerPixel() != 1)
         {
-            Uint32 byteIndex = i / 8;
-            Uint32 bitPos = i % 8;
-            if (frame->pixData[byteIndex] & (1 << bitPos % 8)) {
-                Uint32 targetByteIndex = bitIndex / 8;
-                Uint32 targetBitPos = bitIndex % 8;
-                pixData[targetByteIndex] |= (1 << targetBitPos);
-                DCMSEG_TRACE("Setting bit at targetByteIndex: " << targetByteIndex << ", targetBitPos: " << targetBitPos << ", frame->pixData[" << byteIndex << "]: " << DcmSegUtils::debugByte2Bin(frame->pixData[byteIndex]) << ", value: " << DcmSegUtils::debugByte2Bin(pixData[targetByteIndex]));
+            DCMSEG_ERROR("Cannot concatenate frames with bits allocated != 1");
+            return EC_IllegalParameter;
+        }
+        // Cast the frame to the appropriate type to make access easier
+        DcmIODTypes::Frame<Uint8>* frame = OFstatic_cast(DcmIODTypes::Frame<Uint8>*,frames[frameIndex]);
+        size_t frameBits = rows * cols;
+        // If a frame always has bytes fully packed, i.e. number of bits i a multiple of 8,
+        // we can copy the bytes directly and don't have to fiddle with the bits
+        if (frameBits % 8 == 0)
+        {
+            size_t bytesToCopy = frameBits / 8;
+            memcpy(pixData + (bitIndex / 8), frame->getPixelData(), bytesToCopy);
+            DCMSEG_TRACE("Copying " << bytesToCopy << " bytes from frame " << frameIndex << " to pixData at index " << (bitIndex / 8));
+            bitIndex += frameBits;
+        }
+        else
+        {
+            // we need to copy bitwise, so we iterate over the bits
+            DCMSEG_TRACE("Copying " << frameBits << " bits from frame " << frameIndex << " to pixData at index " << (bitIndex / 8));
+            for (size_t i = 0; i < frameBits; ++i)
+            {
+                size_t byteIndex = i / 8;
+                size_t bitPos = i % 8;
+                if (frame->m_pixData[byteIndex] & (1 << bitPos % 8)) {
+                    size_t targetByteIndex = bitIndex / 8;
+                    size_t targetBitPos = bitIndex % 8;
+                    pixData[targetByteIndex] |= (1 << targetBitPos);
+                    DCMSEG_TRACE("Setting bit at targetByteIndex: " << targetByteIndex << ", targetBitPos: " << targetBitPos << ", frame->pixData[" << byteIndex << "]: " << DcmSegUtils::debugByte2Bin(OFstatic_cast(Uint8*, frame->getPixelData())[byteIndex]) << ", value: " << DcmSegUtils::debugByte2Bin(pixData[targetByteIndex]));
+                }
+                bitIndex++;
             }
-            bitIndex++;
         }
     }
 
@@ -125,7 +98,7 @@ OFCondition DcmSegUtils::concatBinaryFrames(const OFVector<DcmIODTypes::Frame*>&
 }
 
 
-DcmIODTypes::Frame* DcmSegUtils::unpackBinaryFrame(const DcmIODTypes::Frame* frame, Uint16 rows, Uint16 cols)
+DcmIODTypes::Frame<Uint8>* DcmSegUtils::unpackBinaryFrame(const DcmIODTypes::Frame<Uint8>* frame, Uint16 rows, Uint16 cols)
 {
     // Sanity checking
     if ((frame == NULL) || (rows == 0) || (cols == 0))
@@ -138,34 +111,33 @@ DcmIODTypes::Frame* DcmSegUtils::unpackBinaryFrame(const DcmIODTypes::Frame* fra
     Uint32 totalPixels = rows * cols;
 
     // Allocate memory for the unpacked pixel data
-    DcmIODTypes::Frame* result = new DcmIODTypes::Frame();
+    DcmIODTypes::Frame<Uint8>* result = new DcmIODTypes::Frame<Uint8>();
     if (result == NULL)
     {
         DCMSEG_ERROR("Cannot allocate memory for unpacked binary frame");
         return NULL;
     }
-    result->pixData = new Uint8[totalPixels];
-    if (result->pixData == NULL)
+    result->m_pixData = new Uint8[totalPixels];
+    if (result->m_pixData == NULL)
     {
         DCMSEG_ERROR("Cannot allocate memory for unpacked binary frame");
         delete result;
         return NULL;
     }
-    result->length = totalPixels;
-    memset(result->pixData, 0, totalPixels); // Initialize to 0
+    result->m_numPixels = totalPixels;
+    memset(result->m_pixData, 0, totalPixels); // Initialize to 0
 
     // Unpack the bits
     for (Uint32 i = 0; i < totalPixels; ++i) {
         Uint32 byteIndex = i / 8;
         Uint32 bitIndex = i % 8;
-        if (frame->pixData[byteIndex] & (1 << (bitIndex))) {
-            result->pixData[i] = 1;
+        if (frame->m_pixData[byteIndex] & (1 << (bitIndex))) {
+            result->m_pixData[i] = 1;
         } else
         {
-            result->pixData[i] = 0;
+            result->m_pixData[i] = 0;
         }
     }
-
     return result;
 }
 
@@ -197,4 +169,3 @@ OFString DcmSegUtils::debugByte2Bin(Uint8 b)
     }
     return result;
 }
-
index 5636eb01af9c17f06be9ef866e00b4d8792459c3..fb36b784112fbba463c184510eeaceb7902ebe4a 100644 (file)
@@ -1,10 +1,11 @@
 # declare executables
 DCMTK_ADD_TEST_EXECUTABLE(dcmseg_tests
   tbigdim.cc
+  tconcat_binary.cc
   tests.cc
-  tutils.cc
+  tlabelmap.cc
   troundtrip.cc
-  tconcat_binary.cc
+  tutils.cc
 )
 
 # make sure executables are linked to the corresponding libraries
index 91ef09b6db238494c98da4c1944c9a64e77d8422..aab1cc6623f35174cd3bcece03b3404151d6265d 100644 (file)
@@ -76,6 +76,7 @@ tbigdim.o: tbigdim.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
@@ -145,9 +146,10 @@ tconcat_binary.o: tconcat_binary.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
  ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
- ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h ../include/dcmtk/dcmseg/segdoc.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
@@ -157,6 +159,8 @@ tconcat_binary.o: tconcat_binary.cc \
  ../../dcmfg/include/dcmtk/dcmfg/fg.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
@@ -167,7 +171,6 @@ tconcat_binary.o: tconcat_binary.cc \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
@@ -188,10 +191,16 @@ tconcat_binary.o: tconcat_binary.cc \
  ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
  ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
  ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
- ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h \
  ../../ofstd/include/dcmtk/ofstd/oftest.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
  ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
@@ -253,7 +262,146 @@ tests.o: tests.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h
-troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
+tlabelmap.o: tlabelmap.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../include/dcmtk/dcmseg/segdoc.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fg.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/stralias.def \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../ofstd/include/dcmtk/ofstd/oftempf.h
+tpacking.o: tpacking.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmseg/segdoc.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
@@ -319,14 +467,17 @@ troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
  ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
- ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
  ../../dcmfg/include/dcmtk/dcmfg/fg.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
@@ -337,7 +488,6 @@ troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
@@ -358,13 +508,16 @@ troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
  ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
  ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
  ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
- ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
- ../include/dcmtk/dcmseg/segment.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h \
  ../../ofstd/include/dcmtk/ofstd/oftest.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
  ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
@@ -384,34 +537,52 @@ troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
  ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
- ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
  ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
  ../../ofstd/include/dcmtk/ofstd/oftempf.h
-tutils.o: tutils.cc ../../config/include/dcmtk/config/osconfig.h \
- ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
- ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+troundtrip.o: troundtrip.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmseg/segdoc.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
  ../../oflog/include/dcmtk/oflog/oflog.h \
  ../../oflog/include/dcmtk/oflog/logger.h \
  ../../oflog/include/dcmtk/oflog/config.h \
- ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
- ../../ofstd/include/dcmtk/ofstd/ofcast.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
  ../../oflog/include/dcmtk/oflog/config/defines.h \
  ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
  ../../oflog/include/dcmtk/oflog/loglevel.h \
  ../../ofstd/include/dcmtk/ofstd/ofvector.h \
- ../../ofstd/include/dcmtk/ofstd/oftypes.h \
  ../../oflog/include/dcmtk/oflog/tstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstring.h \
- ../../ofstd/include/dcmtk/ofstd/ofstream.h \
  ../../oflog/include/dcmtk/oflog/tchar.h \
  ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
  ../../oflog/include/dcmtk/oflog/appender.h \
  ../../ofstd/include/dcmtk/ofstd/ofmem.h \
  ../../ofstd/include/dcmtk/ofstd/ofutil.h \
- ../../ofstd/include/dcmtk/ofstd/oftraits.h \
  ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
  ../../oflog/include/dcmtk/oflog/layout.h \
  ../../oflog/include/dcmtk/oflog/streams.h \
@@ -423,27 +594,145 @@ tutils.o: tutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../oflog/include/dcmtk/oflog/logmacro.h \
  ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
  ../../oflog/include/dcmtk/oflog/tracelog.h \
- ../../ofstd/include/dcmtk/ofstd/ofcond.h \
- ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
- ../../ofstd/include/dcmtk/ofstd/diag/push.def \
- ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
- ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationcreator.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../dcmfg/include/dcmtk/dcmfg/concatenationloader.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fg.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgseg.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/stralias.def \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modiccprofile.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsegmentationseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h \
+ ../include/dcmtk/dcmseg/segdef.h ../include/dcmtk/dcmseg/segment.h \
+ ../include/dcmtk/dcmseg/segtypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrst.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrut.h \
+ ../include/dcmtk/dcmseg/segutils.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../ofstd/include/dcmtk/ofstd/oftempf.h
+tutils.o: tutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmseg/segutils.h ../include/dcmtk/dcmseg/segdef.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../include/dcmtk/dcmseg/segtypes.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
  ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
  ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
  ../../ofstd/include/dcmtk/ofstd/ofthread.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
  ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
  ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
@@ -455,6 +744,9 @@ tutils.o: tutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/oflist.h \
  ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
@@ -472,4 +764,5 @@ tutils.o: tutils.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
  ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
  ../../ofstd/include/dcmtk/ofstd/ofexit.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcuid.h
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h
index 1ec50ada88eb66f3f4acc6a102bfeae2ea49be28..4a4dee07956b45a4000003b2b640b93c60f27225 100644 (file)
@@ -18,16 +18,19 @@ oflogdir = $(top_srcdir)/../oflog
 dcmdatadir = $(top_srcdir)/../dcmdata
 dcmioddir = $(top_srcdir)/../dcmiod
 dcmfgdir = $(top_srcdir)/../dcmfg
+dcmimgledir = $(top_srcdir)/../dcmimgle
 
 LIBDIRS = -L$(top_srcdir)/libsrc -L$(ofstddir)/libsrc -L$(oflogdir)/libsrc \
        -L$(dcmdatadir)/libsrc -L$(dcmioddir)/libsrc -L$(dcmfgdir)/libsrc \
-       -L$(oficonvdir)/libsrc
-LOCALLIBS = -ldcmseg -ldcmfg -ldcmiod -ldcmdata -loflog -lofstd -loficonv $(ZLIBLIBS) \
-       $(CHARCONVLIBS) $(MATHLIBS)
+       -L$(oficonvdir)/libsrc -L$(dcmimgledir)/libsrc
+
+LOCALLIBS = -ldcmseg -ldcmfg -ldcmiod -ldcmimgle -ldcmdata \
+       -loflog -lofstd -loficonv $(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS)
+
 LOCALINCLUDES = -I$(top_srcdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
-       -I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include \
+       -I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include
 
-test_objs = tbigdim.o tconcat_binary.o tests.o troundtrip.o tutils.o
+test_objs = tbigdim.o tconcat_binary.o tests.o tlabelmap.o troundtrip.o tutils.o
 objs = $(test_objs)
 progs = tests
 
index 6098e14b819866bb44d636f97023ff17395cf7e4..988bc83d21b9ab1858d51dca23911379662a495d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2022-2024, OFFIS e.V.
+ *  Copyright (C) 2022-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -23,6 +23,7 @@
 #include "dcmtk/ofstd/oftest.h"
 #include "dcmtk/dcmseg/segtypes.h" /* for DCMSEG_DEBUG */
 
+// DCMTK's original OFMap implementation is too slow for this test...
 #ifdef HAVE_STL_MAP
 #include "dcmtk/dcmseg/segdoc.h"
 #include "dcmtk/dcmseg/segment.h"
@@ -31,7 +32,6 @@
 #include "dcmtk/dcmfg/fgpixmsr.h"
 #include "dcmtk/dcmfg/fgplanor.h"
 #include "dcmtk/dcmfg/fgplanpo.h"
-#include "dcmtk/dcmfg/fgseg.h"
 #include "dcmtk/dcmiod/iodmacro.h"
 #include "dcmtk/dcmdata/dcxfer.h"
 #include "dcmtk/dcmdata/dcdict.h"
 
 static const Uint8 NUM_ROWS             = 5;
 static const Uint8 NUM_COLS             = 5;
+static const Uint8 NUM_THREADS          = 16; // Use 16 threads for writing and reading
 
 // Restrict to 1.000.000 Frames since the theoretical 2^31-1 number of frames
 // results in too much memory usage and waiting time
+
 static const Uint32 NUM_FRAMES           = 1000000;
-static const Uint16 NUM_SEGS             = DCM_SEG_MAX_SEGMENTS;
+static const size_t NUM_SEGS             = DCM_SEG_MAX_SEGMENTS;
 
 static const Uint8 NUM_PIXELS_PER_FRAME = NUM_COLS * NUM_ROWS;
 
@@ -79,6 +81,7 @@ OFTEST_FLAGS(dcmseg_bigdim, EF_Slow)
     DcmDataset* ds = dcmff.getDataset();
     seg->setCheckDimensionsOnWrite(OFFalse);
     seg->setCheckFGOnWrite(OFFalse);
+    seg->getFunctionalGroups().setUseThreads(NUM_THREADS);
     OFCondition result = seg->writeDataset(*ds);
     OFCHECK(result.good());
 
@@ -87,19 +90,23 @@ OFTEST_FLAGS(dcmseg_bigdim, EF_Slow)
     OFString temp_fn = tf.getFilename();
     OFCHECK(!temp_fn.empty());
     OFCHECK(dcmff.saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+    tf.stealFile();
 
     // Read object from dataset into DcmSegmentation object, write again to dataset and
     // check whether object after writing is identical to object after writing.
     // the same expected result
     delete seg;
     seg = NULL;
-    DcmSegmentation::loadFile(temp_fn, seg).good();
+    DcmSegmentation::LoadingFlags flags;
+    flags.m_numThreads = NUM_THREADS; // Use 16 threads for reading
+    DcmSegmentation::loadFile(temp_fn, seg, flags).good();
     OFCHECK(seg != OFnullptr);
     if (seg)
     {
         DcmDataset dset;
         seg->setCheckDimensionsOnWrite(OFFalse);
         seg->setCheckFGOnWrite(OFFalse);
+        seg->getFunctionalGroups().setUseThreads(NUM_THREADS);
         OFCHECK(seg->writeDataset(dset).good());
         checkCreatedObject(dset);
         delete seg;
@@ -192,9 +199,8 @@ static void addFrames(DcmSegmentation* seg)
     if (!seg)
         return;
 
-    FGSegmentation* fg_seg = new FGSegmentation();
     FGFrameContent* fg     = new FGFrameContent();
-    OFCHECK(fg && fg_seg);
+    OFCHECK(fg);
     fg->setStackID("1");
     if (fg)
     {
@@ -218,16 +224,14 @@ static void addFrames(DcmSegmentation* seg)
             {
                 data[i] = i;
             }
-            OFCHECK(fg_seg->setReferencedSegmentNumber(frameNo % (DCM_SEG_MAX_SEGMENTS + 1)).good()); // limit/loop to 16 bit
+            Uint16 segmentNumber = OFstatic_cast(Uint16, ((frameNo-1) % (NUM_SEGS)) +1); // segment numbers start at 1
             OFVector<FGBase*> perFrameFGs;
             perFrameFGs.push_back(fg);
-            perFrameFGs.push_back(fg_seg);
-            OFCHECK(seg->addFrame(data, frameNo % (DCM_SEG_MAX_SEGMENTS + 1), perFrameFGs).good());
+            OFCHECK(seg->addFrame(data, segmentNumber, perFrameFGs).good());
             delete[] data;
         }
     }
     delete fg;
-    delete fg_seg;
 }
 
 static void addDimensions(DcmSegmentation* seg)
@@ -278,10 +282,12 @@ static void checkCreatedObject(DcmDataset& dset)
     OFCHECK(dset.findAndGetSequence(DCM_PerFrameFunctionalGroupsSequence, seq).good());
     if (seq != NULL)
     {
-        size_t card = seq->card();
-        OFCHECK(card == NUM_FRAMES);
+        size_t numFrames = seq->card();
+        OFOStringStream oss;
+        oss << "Expected " << NUM_FRAMES << " frames, but got " << numFrames;
+        OFCHECK_MSG(numFrames == NUM_FRAMES, oss.str().c_str());
         DcmItem* item = seq->getItem(0);
-        for (size_t n = 0; (n < card) && (item != NULL); n++)
+        for (size_t n = 0; (n < numFrames) && (item != NULL); n++)
         {
             DcmItem* fgItem = NULL;
             OFCHECK(item->findAndGetSequenceItem(DCM_SegmentIdentificationSequence, fgItem, 0).good());
@@ -289,7 +295,7 @@ static void checkCreatedObject(DcmDataset& dset)
             {
                 Uint16 segNum = 0;
                 OFCHECK(fgItem->findAndGetUint16(DCM_ReferencedSegmentNumber, segNum).good());
-                OFCHECK(segNum == ((n + 1) % (DCM_SEG_MAX_SEGMENTS + 1)));
+                OFCHECK(segNum == ((n % NUM_SEGS) + 1));
 
             }
             item = OFstatic_cast(DcmItem*, seq->nextInContainer(item));
index 04a25be6494dd3db6f9f501f14e0d140ad9d939a..148fb611ddbfbfbc763e6465d932d4594bb3d62e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -51,10 +51,12 @@ OFTEST(dcmseg_concat_binary)
     {
         ConcatenationCreator cc;
         result = cc.setCfgFramesPerInstance(NUM_FRAMES_PER_CONCAT);
+        OFCHECK_MSG(result.good(), "Could not configure Concatenation Frames per Instance");
         if (result.good())
         {
             seg->setCheckFGOnWrite(OFFalse);
             result = seg->writeConcatenation(cc);
+            OFCHECK_MSG(result.good(), "Could not write Concatenation");
             if (result.good())
             {
                 size_t n = 0;
@@ -95,7 +97,7 @@ OFTEST(dcmseg_concat_binary)
         {
             if (cl.getInfo().size() == 1)
             {
-                OFVector<DcmIODTypes::Frame*> frames;
+                OFVector<DcmIODTypes::Frame<Uint8>*> frames;
                 DcmFileFormat dcmff;
                 result = DcmSegmentation::loadConcatenation(cl, cl.getInfo().begin()->first, seg);
                 if (result.good())
index 57a60a9122faac36a3c31212960063182bd0ceb8..431345efd010fdc332fdb28f25073af259f78a69 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, OFFIS e.V.
+ *  Copyright (C) 2015-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -30,5 +30,8 @@ OFTEST_REGISTER(dcmseg_packAndUnpackBinaryFrame);
 OFTEST_REGISTER(dcmseg_concatBinaryFrames);
 OFTEST_REGISTER(dcmseg_roundtrip);
 OFTEST_REGISTER(dcmseg_concat_binary);
-
+OFTEST_REGISTER(dcmseg_labelmap_8bit_mono2);
+OFTEST_REGISTER(dcmseg_labelmap_16bit_mono2);
+OFTEST_REGISTER(dcmseg_labelmap_8bit_palette);
+OFTEST_REGISTER(dcmseg_labelmap_16bit_palette);
 OFTEST_MAIN("dcmseg")
diff --git a/dcmseg/tests/tlabelmap.cc b/dcmseg/tests/tlabelmap.cc
new file mode 100644 (file)
index 0000000..af0e110
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, Open Connections GmbH
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmseg
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Test for creating, writing and reading labelmap segmentations
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+
+#include "dcmtk/dcmdata/dcdatset.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dcsequen.h"
+#include "dcmtk/dcmiod/modpalettecolorlut.h"
+#include "dcmtk/dcmseg/segdoc.h"
+#include "dcmtk/dcmseg/segment.h"
+#include "dcmtk/dcmseg/segtypes.h"
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/dcmfg/fgfracon.h"
+#include "dcmtk/dcmfg/fgpixmsr.h"
+#include "dcmtk/dcmfg/fgplanor.h"
+#include "dcmtk/dcmfg/fgplanpo.h"
+#include "dcmtk/dcmiod/iodmacro.h"
+#include "dcmtk/dcmdata/dcxfer.h"
+#include "dcmtk/dcmdata/dcdict.h"
+#include "dcmtk/ofstd/ofmem.h"
+#include "dcmtk/ofstd/oftempf.h"
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+// Dimensions are 510 x 257 = 65535 pixels per frame.
+// This allows to count through 16 bit values from 0 to 65534 for each frame. We are not using value
+// up to 65535 since that would result in 65536 values; since each value represents a segment requiring
+// an entry in the Segment Sequence, we would exceed the maximum number of segments (65535) allowed in
+// a segmentation object (Segment Number is of VR US).
+// For 8 bit, the pixel are counted through repeatedly from 0 to 255. This does not match exactly on the
+// number of pixels (510*257) per frame but should be sufficient for testing purposes. 255 is chosen
+// because this will also exercise the maximum number of palette entries (256) in the palette color LUT.
+static const Uint16 NUM_ROWS             = 510;
+static const Uint16 NUM_COLS             = 257;
+// Two frames to exercise multi-frame
+static const Uint16 NUM_FRAMES            = 2;
+static const size_t NUM_PIXELS_PER_FRAME = NUM_COLS * NUM_ROWS;
+
+
+// set to true to keep temporary files for debugging
+static const OFBool keepTempFiles = OFFalse;
+
+// For 8 bit, pixel values 0 to 255 are permitted.
+// For 16 bit, pixel values 0 to 65534 are permitted, since for labelmaps the pixel
+// value represents the segment number as well, and DICOM permits a maximum segment number
+// of 65535.
+
+// Since the number of segments in the 16 bit case is very large and generation takes
+// some time, the 16 bits are marked as slow.
+
+static DcmSegmentation* createLabelMap(const Uint8 bits_allocated, const DcmSegTypes::E_SegmentationLabelmapColorModel cm);
+static void setGenericValues(DcmSegmentation* seg);
+static void addSharedFGs(DcmSegmentation* seg);
+static void addPaletteAndICCProfile(DcmSegmentation* seg, const Uint8 bitsAllocated);
+template<typename T>
+static void addFrames(DcmSegmentation* seg, const Uint8 bitsAllocated);
+static void addSegments(DcmSegmentation *seg, const Uint8 bitsAllocated);
+static void addDimensions(DcmSegmentation* seg);
+static void checkCreatedObject(DcmDataset* dset, const Uint8 bits_allocated, const DcmSegTypes::E_SegmentationLabelmapColorModel cm);
+static void checkPalette(DcmDataset* dset, const Uint8 bits_allocated);
+
+
+// Concatenations tests: TBD
+// static void writeAndCheckConcatenation(DcmSegmentation* seg, OFList<OFFilename>& concats);
+// static void loadAndCheckConcatenation(const OFList<OFFilename>& concats);
+// static void checkConcatenationInstance(size_t numInstance, DcmSegmentation* srcInstance, DcmDataset* concatInstance);
+
+OFTEST(dcmseg_labelmap_8bit_mono2)
+{
+    // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return;
+    }
+
+    // Creation
+    DcmSegmentation* seg = createLabelMap(8, DcmSegTypes::SLCM_MONOCHROME2);
+    setGenericValues(seg);
+    addSharedFGs(seg);
+    addFrames<Uint8>(seg, 8);
+    addSegments(seg, 8);
+    addDimensions(seg);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+    DcmDataset* created_ds = dcmff.getDataset();
+    OFCHECK(seg->writeDataset(*created_ds).good());
+    checkCreatedObject(created_ds, 8, DcmSegTypes::SLCM_MONOCHROME2);
+
+    // Save to disk, and re-load to test import
+    OFTempFile tf;
+    OFString temp_fn = tf.getFilename();
+    OFCHECK(!temp_fn.empty());
+    OFCHECK(seg->saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+
+    // Read object from dataset into DcmSegmentation object, write again to dataset and
+    // check whether object after writing is identical to object after writing.
+    // the same expected result
+    delete seg;
+    seg = NULL;
+    DcmDataset loaded_ds;
+    DcmSegmentation::loadFile(temp_fn, seg).good();
+    OFCHECK(seg != OFnullptr);
+    if (seg)
+    {
+        OFCHECK(seg->writeDataset(loaded_ds).good());
+        checkCreatedObject(&loaded_ds, 8, DcmSegTypes::SLCM_MONOCHROME2);
+    }
+    if (keepTempFiles)
+    {
+        std::cout << "Keeping temporary file: " << temp_fn << " from test dcmseg_labelmap_8bit_mono2" << std::endl;
+        tf.stealFile();
+    }
+    delete seg;
+}
+
+
+OFTEST_FLAGS(dcmseg_labelmap_16bit_mono2, EF_Slow)
+{
+    // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return;
+    }
+
+    // Creation
+    DcmSegmentation* seg_object = createLabelMap(16, DcmSegTypes::SLCM_MONOCHROME2);
+    setGenericValues(seg_object);
+    addSharedFGs(seg_object);
+    addFrames<Uint16>(seg_object, 16);
+    addSegments(seg_object, 16);
+    addDimensions(seg_object);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+    DcmDataset* dset_created = dcmff.getDataset();
+    OFCHECK(seg_object->writeDataset(*dset_created).good());
+    checkCreatedObject(dset_created, 16, DcmSegTypes::SLCM_MONOCHROME2);
+
+    // Save to disk, and re-load to test import
+    OFTempFile tf;
+    OFString temp_fn = tf.getFilename();
+    OFCHECK(!temp_fn.empty());
+    OFCHECK(seg_object->saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+
+    // Read object from dataset into DcmSegmentation object, write again to dataset and
+    // check whether object after writing is identical to object after writing.
+    // the same expected result
+    delete seg_object;
+    seg_object = NULL;
+    DcmSegmentation::loadFile(temp_fn, seg_object).good();
+    OFCHECK(seg_object != OFnullptr);
+    DcmDataset dset_loaded;
+    if (seg_object)
+    {
+        OFCHECK(seg_object->writeDataset(dset_loaded).good());
+        checkCreatedObject(&dset_loaded, 16, DcmSegTypes::SLCM_MONOCHROME2);
+    }
+
+    delete seg_object;
+    if (keepTempFiles)
+    {
+        std::cout << "Keeping temporary file: " << temp_fn << " from test dcmseg_labelmap_16bit_mono2" << std::endl;
+        tf.stealFile();
+    }
+}
+
+OFTEST(dcmseg_labelmap_8bit_palette)
+{
+    // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return;
+    }
+
+    // Creation
+    DcmSegmentation* seg = createLabelMap(8, DcmSegTypes::SLCM_PALETTE);
+    setGenericValues(seg);
+    addSharedFGs(seg);
+    addFrames<Uint8>(seg, 8);
+    addSegments(seg, 8);
+    addDimensions(seg);
+    addPaletteAndICCProfile(seg, 8);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+    DcmDataset* created_ds = dcmff.getDataset();
+    OFCHECK(seg->writeDataset(*created_ds).good());
+    checkCreatedObject(created_ds, 8, DcmSegTypes::SLCM_PALETTE);
+
+    // Save to disk, and re-load to test import
+    OFTempFile tf;
+    OFString temp_fn = tf.getFilename();
+    OFCHECK(!temp_fn.empty());
+    OFCHECK(seg->saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+
+    // Read object from dataset into DcmSegmentation object, write again to dataset and
+    // check whether object after writing is identical to object after writing.
+    // the same expected result
+    delete seg;
+    seg = NULL;
+    DcmDataset loaded_ds;
+    DcmSegmentation::loadFile(temp_fn, seg).good();
+    OFCHECK(seg != OFnullptr);
+    if (seg)
+    {
+        seg->writeDataset(loaded_ds).good();
+        checkCreatedObject(&loaded_ds, 8, DcmSegTypes::SLCM_PALETTE);
+    }
+
+    delete seg;
+    if (keepTempFiles)
+    {
+        std::cout << "Keeping temporary file: " << temp_fn << " from test dcmseg_labelmap_8bit_palette" << std::endl;
+        tf.stealFile();
+    }
+}
+
+
+OFTEST_FLAGS(dcmseg_labelmap_16bit_palette, EF_Slow)
+{
+    // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return;
+    }
+
+    // Creation
+    DcmSegmentation* seg_object = createLabelMap(16, DcmSegTypes::SLCM_PALETTE);
+    setGenericValues(seg_object);
+    addSharedFGs(seg_object);
+    addFrames<Uint16>(seg_object, 16);
+    addSegments(seg_object, 16);
+    addDimensions(seg_object);
+    addPaletteAndICCProfile(seg_object, 16);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+    DcmDataset* dset_created = dcmff.getDataset();
+    OFCHECK(seg_object->writeDataset(*dset_created).good());
+    checkCreatedObject(dset_created, 16, DcmSegTypes::SLCM_PALETTE);
+
+    // Save to disk, and re-load to test import
+    OFTempFile tf;
+    OFString temp_fn = tf.getFilename();
+    OFCHECK(!temp_fn.empty());
+    OFCHECK(seg_object->saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+
+    // Read object from dataset into DcmSegmentation object, write again to dataset and
+    // check whether object after writing is identical to object after writing.
+    // the same expected result
+    delete seg_object;
+    seg_object = NULL;
+    DcmSegmentation::loadFile(temp_fn, seg_object).good();
+    OFCHECK(seg_object != OFnullptr);
+    DcmDataset dset_loaded;
+    if (seg_object)
+    {
+        seg_object->writeDataset(dset_loaded).good();
+        checkCreatedObject(&dset_loaded, 16, DcmSegTypes::SLCM_PALETTE);
+    }
+
+    delete seg_object;
+    if (keepTempFiles)
+    {
+        std::cout << "Keeping temporary file: " << temp_fn << " from test dcmseg_labelmap_16bit_palette" << std::endl;
+        tf.stealFile();
+    }
+}
+
+
+static DcmSegmentation* createLabelMap(const Uint8 bits_allocated, const DcmSegTypes::E_SegmentationLabelmapColorModel cm)
+{
+    IODGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
+    ContentIdentificationMacro ci("1", "LABEL", "DESCRIPTION", "Doe^John");
+    DcmSegmentation* seg = NULL;
+    OFCondition result;
+    DcmSegmentation::createLabelmapSegmentation(seg, NUM_ROWS, NUM_COLS, eq, ci, bits_allocated == 16, cm);
+    OFCHECK(result.good());
+    OFCHECK(seg != OFnullptr);
+    return seg;
+}
+
+static void setGenericValues(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+    OFCHECK(seg->getPatient().setPatientName("Bond^James").good());
+    OFCHECK(seg->getPatient().setPatientID("007").good());
+    OFCHECK(seg->getPatient().setPatientBirthDate("19771007").good());
+    OFCHECK(seg->getStudy().setStudyDate("20190801").good());
+    OFCHECK(seg->getStudy().setStudyTime("120000").good());
+    OFCHECK(seg->getStudy().setStudyID("1").good());
+    OFCHECK(seg->getPatientStudy().setPatientAge("040Y").good());
+    OFCHECK(seg->getSeries().setSeriesDescription("Test Description").good());
+    OFCHECK(seg->getSeries().setSeriesNumber("1").good());
+    OFCHECK(seg->getSeries().setPatientPosition("HFS").good());
+
+    // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
+    // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
+    // so that they are not overwritten with new, automatically created values later.
+    OFCHECK(seg->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
+    OFCHECK(seg->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
+    OFCHECK(seg->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
+    OFCHECK(seg->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
+    OFCHECK(seg->getGeneralImage().setContentDate("20190927").good());
+    OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
+    OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
+}
+
+
+static void addSharedFGs(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+
+    FGPixelMeasures meas;
+    OFCHECK(meas.setPixelSpacing("0.1\\0.1").good());
+    OFCHECK(meas.setSliceThickness("1.0").good());
+    OFCHECK(meas.setSpacingBetweenSlices("0.05").good());
+
+    FGPlanePosPatient planpo;
+    OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good());
+
+    FGPlaneOrientationPatient planor;
+    OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good());
+
+    OFCHECK(seg->addForAllFrames(meas).good());
+    OFCHECK(seg->addForAllFrames(planpo).good());
+    OFCHECK(seg->addForAllFrames(planor).good());
+}
+
+template<typename T>
+static void addFrames(DcmSegmentation* seg, const Uint8 bitsAllocated)
+{
+    if (!seg)
+        return;
+
+    FGFrameContent* fg     = new FGFrameContent();
+    OFCHECK(fg);
+    fg->setStackID("1");
+    if (fg)
+    {
+        for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++)
+        {
+            OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good());
+            OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good());
+            OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good());
+            OFCHECK(fg->setFrameAcquisitionDuration(0.001).good());
+            OFCHECK(fg->setInStackPositionNumber(frameNo).good());
+            OFCHECK(fg->setDimensionIndexValues(1, 0).good());
+            OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good());
+            OFVector<FGBase*> groups;
+            groups.push_back(fg);
+            T* data = new T[NUM_PIXELS_PER_FRAME];
+            Uint32 max_value = (bitsAllocated == 16 ? 65535 : 256);
+            for (Uint32 i = 0; i < NUM_PIXELS_PER_FRAME; ++i)
+            {
+                data[i] = OFstatic_cast(T, (NUM_PIXELS_PER_FRAME * (frameNo - 1) + i) % max_value);
+            }
+            OFVector<FGBase*> perFrameFGs;
+            perFrameFGs.push_back(fg);
+            OFCHECK(seg->addFrame<T>(data, frameNo, perFrameFGs).good());
+            delete[] data;
+        }
+    }
+    delete fg;
+}
+
+static void addSegments(DcmSegmentation *seg, const Uint8 bitsAllocated)
+{
+    for (Uint32 i = 0; i < ((bitsAllocated == 16) ? 65535u : 255u); i++)
+    {
+        DcmSegment* segment = NULL;
+        CodeSequenceMacro category("85756007", "SCT", "Tissue");
+        CodeSequenceMacro propType("51114001", "SCT", "Artery");
+
+        OFCHECK(DcmSegment::create(segment, "SEGLABEL", category, propType, DcmSegTypes::SAT_AUTOMATIC, "OC_DUMMY")
+                    .good());
+        OFCHECK(segment != OFnullptr);
+        Uint16 segno = OFstatic_cast(Uint16, i);
+        OFCHECK(seg->addSegment(segment, segno).good());
+    }
+}
+
+
+static void addDimensions(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+    IODMultiframeDimensionModule& dims = seg->getDimensions();
+    OFCHECK(dims.addDimensionIndex(
+                    DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM")
+                .good());
+    OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber,
+                                   "2.25.30855560781715986879861690673941231222",
+                                   DCM_FrameContentSequence,
+                                   "STACK_DIM")
+                .good());
+    OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org(
+        new IODMultiframeDimensionModule::DimensionOrganizationItem);
+    if (org)
+    {
+        org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222");
+        dims.getDimensionOrganizationSequence().push_back(org.release());
+    }
+}
+
+
+static void checkCreatedObject(DcmDataset* dset, const Uint8 bits_allocated, const DcmSegTypes::E_SegmentationLabelmapColorModel cm)
+{
+    // Check imaging parameters
+    Uint16 uint16;
+    OFString str;
+    OFCHECK(dset->findAndGetUint16(DCM_BitsAllocated, uint16).good());
+    OFCHECK(uint16 == bits_allocated);
+    OFCHECK(dset->findAndGetUint16(DCM_BitsStored, uint16).good());
+    OFCHECK(uint16 == bits_allocated);
+    OFCHECK(dset->findAndGetUint16(DCM_HighBit, uint16).good());
+    OFCHECK(uint16 == bits_allocated - 1);
+    OFCHECK(dset->findAndGetUint16(DCM_SamplesPerPixel, uint16).good());
+    OFCHECK(uint16 == 1);
+    OFCHECK(dset->findAndGetUint16(DCM_PixelRepresentation, uint16).good());
+    OFCHECK(uint16 == 0);
+    OFCHECK(dset->findAndGetOFString(DCM_PhotometricInterpretation, str).good());
+    if (cm == DcmSegTypes::SLCM_MONOCHROME2)
+    {
+        OFCHECK(str == "MONOCHROME2");
+    }
+    else
+    {
+        OFCHECK(str == "PALETTE COLOR");
+        checkPalette(dset, bits_allocated);
+    }
+    Sint32 numFrames = 0;
+    OFCHECK(dset->findAndGetSint32(DCM_NumberOfFrames, numFrames).good());
+    OFCHECK(numFrames > 0);
+    OFCHECK(OFstatic_cast(Uint16, numFrames) == NUM_FRAMES);
+    OFCHECK(dset->findAndGetUint16(DCM_Rows, uint16).good());
+    OFCHECK(uint16 == NUM_ROWS);
+    OFCHECK(dset->findAndGetUint16(DCM_Columns, uint16).good());
+    OFCHECK(uint16 == NUM_COLS);
+    OFCHECK(dset->findAndGetOFString(DCM_SegmentationType, str).good());
+    OFCHECK(DcmSegTypes::OFString2Segtype(str) == DcmSegTypes::ST_LABELMAP);
+
+    // Check pixel data
+    if (bits_allocated == 8)
+    {
+        const Uint8* pixData = NULL;
+        OFCHECK(dset->findAndGetUint8Array(DCM_PixelData, pixData).good());
+        OFCHECK(pixData != NULL);
+        if (pixData)
+        {
+            Uint16 max_value = 256;
+            Uint32 numPixels = NUM_ROWS * NUM_COLS * NUM_FRAMES;
+            for (Uint32 i = 0; i < numPixels; i++)
+            {
+                OFCHECK(pixData[i] == OFstatic_cast(Uint8, i % max_value));
+            }
+        }
+        // pixData contains only reference, no need to delete
+    }
+    else if (bits_allocated == 16)
+    {
+        const Uint16* pixData = NULL;
+        OFCHECK(dset->findAndGetUint16Array(DCM_PixelData, pixData).good());
+        OFCHECK(pixData != NULL);
+        if (pixData)
+        {
+            for (Uint32 i = 0; i < NUM_PIXELS_PER_FRAME * numFrames; i++)
+            {
+                OFCHECK(pixData[i] == OFstatic_cast(Uint16, i % 65535));
+                // report expected and actual value in case of mismatch
+                if (pixData[i] != OFstatic_cast(Uint16, i % 65535))
+                {
+                    DCMSEG_DEBUG("Expected at index " << i << ": " << OFstatic_cast(Uint16, i % 65535) << ", actual value: " << pixData[i]);
+                }
+            }
+        }
+        // pixData contains only reference, no need to delete
+    }
+
+    // check segments
+    DcmSequenceOfItems* seq = NULL;
+    OFCHECK(dset->findAndGetSequence(DCM_SegmentSequence, seq).good());
+    OFCHECK(seq != NULL);
+    if (seq)
+    {
+        OFCHECK(seq->card() == ((bits_allocated == 16) ? 65535u : 255u));
+    }
+    // check that there is no Segmentation FG
+    DcmElement *fgSeq = NULL;
+    OFCHECK(dset->findAndGetElement(DCM_SegmentIdentificationSequence, fgSeq, OFTrue /* search into sub */).bad());
+}
+
+static void addPaletteAndICCProfile(DcmSegmentation* seg, const Uint8 bitsAllocated)
+{
+    if (bitsAllocated == 8)
+    {
+        IODPaletteColorLUTModule& pal8 = seg->getPaletteColorLUT();
+        OFCHECK(pal8.setRedPaletteColorLookupTableDescriptor(255, 0, 8).good());
+        OFCHECK(pal8.setGreenPaletteColorLookupTableDescriptor(255, 0, 8).good());
+        OFCHECK(pal8.setBluePaletteColorLookupTableDescriptor(255, 0, 8).good());
+        // re-use the same data for all entries
+        const Uint8 MAX_8BIT_ENTRIES = 255;
+        Uint8* data = new Uint8[MAX_8BIT_ENTRIES];
+        for (Uint16 i = 0; i < MAX_8BIT_ENTRIES; i++)
+        {
+            data[i] = OFstatic_cast(Uint8, i);
+        }
+        OFCHECK(pal8.setRedPaletteColorLookupTableData(data, MAX_8BIT_ENTRIES).good());
+        OFCHECK(pal8.setGreenPaletteColorLookupTableData(data, MAX_8BIT_ENTRIES).good());
+        OFCHECK(pal8.setBluePaletteColorLookupTableData(data, MAX_8BIT_ENTRIES).good());
+        delete [] data;
+    }
+    else if (bitsAllocated == 16)
+    {
+        IODPaletteColorLUTModule& pal16= seg->getPaletteColorLUT();
+        OFCHECK(pal16.setRedPaletteColorLookupTableDescriptor(65535, 0, 16).good());
+        OFCHECK(pal16.setGreenPaletteColorLookupTableDescriptor(65535, 0, 16).good());
+        OFCHECK(pal16.setBluePaletteColorLookupTableDescriptor(65535, 0, 16).good());
+        // re-use the same data for all entries
+        Uint16* data = new Uint16[65536];
+        for (Uint16 i = 0; i < 65535u; i++) // TODO
+        {
+            data[i] = i;
+        }
+        OFCHECK(pal16.setRedPaletteColorLookupTableData(data, 65535).good());
+        OFCHECK(pal16.setGreenPaletteColorLookupTableData(data, 65535).good());
+        OFCHECK(pal16.setBluePaletteColorLookupTableData(data, 65535).good());
+        delete [] data;
+    }
+    else
+    {
+        OFCHECK_FAIL("Unsupported value for bitsAllocated");
+        return;
+    }
+    // Palette Color LUT Module requires ICC profile information.
+    // Create ICC profile dummy data which is definitely not a valid ICC profile,
+    // but should be sufficient for testing purposes.
+    const size_t ICC_LENGTH = 256; // length of ICC profile in bytes
+    Uint8* iccProfile = new Uint8[ICC_LENGTH];
+    for (size_t i = 0; i < ICC_LENGTH; i++)
+    {
+        iccProfile[i] = OFstatic_cast(Uint8, i);
+    }
+    OFCHECK(seg->getICCProfile().setICCProfile(iccProfile, ICC_LENGTH, OFTrue /* check */).good());
+    OFCHECK(seg->getICCProfile().setColorSpace("SRGB", OFTrue /* check */).good());
+    delete[] iccProfile;
+}
+
+static void checkPalette(DcmDataset* dset, const Uint8 bitsAllocated)
+{
+    if (bitsAllocated == 8)
+    {
+        Uint8 MAX_ENTRIES_8_BIT = 255;
+        IODPaletteColorLUTModule pal8;
+        OFCHECK(pal8.read(*dset).good());
+        Uint16 numEntries, firstEntry, bits;
+        OFCHECK(pal8.getRedPaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal8.getRedPaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal8.getRedPaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == 255);
+        OFCHECK(firstEntry == 0);
+        OFCHECK(bits == bitsAllocated);
+        OFCHECK(pal8.getGreenPaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal8.getGreenPaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal8.getGreenPaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == MAX_ENTRIES_8_BIT);
+        OFCHECK(firstEntry == 0);
+        OFCHECK(bits == bitsAllocated);
+        OFCHECK(pal8.getBluePaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal8.getBluePaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal8.getBluePaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == MAX_ENTRIES_8_BIT);
+        OFCHECK(firstEntry == 0);
+        OFCHECK(bits == bitsAllocated);
+
+        const Uint8* redData = NULL;
+        const Uint8* greenData = NULL;
+        const Uint8* blueData = NULL;
+        unsigned long numEntriesRed, numEntriesGreen, numEntriesBlue;
+        OFCHECK(pal8.getRedPaletteColorLookupTableData(redData, numEntriesRed).good());
+        OFCHECK(pal8.getGreenPaletteColorLookupTableData(greenData, numEntriesGreen).good());
+        OFCHECK(pal8.getBluePaletteColorLookupTableData(blueData, numEntriesBlue).good());
+        OFCHECK(numEntriesRed == MAX_ENTRIES_8_BIT);
+        OFCHECK(numEntriesBlue == MAX_ENTRIES_8_BIT);
+        OFCHECK(numEntriesGreen == MAX_ENTRIES_8_BIT);
+        OFCHECK(redData != NULL);
+        OFCHECK(greenData != NULL);
+        OFCHECK(blueData != NULL);
+        if (redData && greenData && blueData)
+        {
+            for (Uint32 i = 0; i < MAX_ENTRIES_8_BIT; i++)
+            {
+                OFCHECK(redData[i] == OFstatic_cast(Uint8, i));
+                OFCHECK(greenData[i] == OFstatic_cast(Uint8, i));
+                OFCHECK(blueData[i] == OFstatic_cast(Uint8, i));
+            }
+        }
+        delete[] redData;
+        delete[] greenData;
+        delete[] blueData;
+    }
+    else if (bitsAllocated == 16)
+    {
+        IODPaletteColorLUTModule pal16;
+        OFCHECK(pal16.read(*dset).good());
+        Uint16 numEntries, firstEntry, bits;
+        OFCHECK(pal16.getRedPaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal16.getRedPaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal16.getRedPaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == 65535);
+        OFCHECK(firstEntry == 0);
+        OFCHECK(bits == bitsAllocated);
+        OFCHECK(pal16.getGreenPaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal16.getGreenPaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal16.getGreenPaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == 65535);
+        OFCHECK(firstEntry == 0);
+        OFCHECK(bits == bitsAllocated);
+        OFCHECK(pal16.getBluePaletteColorLookupTableDescriptor(numEntries, 0).good());
+        OFCHECK(pal16.getBluePaletteColorLookupTableDescriptor(firstEntry, 1).good());
+        OFCHECK(pal16.getBluePaletteColorLookupTableDescriptor(bits, 2).good());
+        OFCHECK(numEntries == 65535);
+        OFCHECK(firstEntry == 0 );
+        OFCHECK(bits == bitsAllocated);
+
+        const Uint16* redData = NULL;
+        const Uint16* greenData = NULL;
+        const Uint16* blueData = NULL;
+        unsigned long numEntriesRed, numEntriesGreen, numEntriesBlue;
+        OFCHECK(pal16.getRedPaletteColorLookupTableData(redData, numEntriesRed).good());
+        OFCHECK(pal16.getGreenPaletteColorLookupTableData(greenData, numEntriesGreen).good());
+        OFCHECK(pal16.getBluePaletteColorLookupTableData(blueData, numEntriesBlue).good());
+        OFCHECK(numEntriesRed == 65535);
+        OFCHECK(numEntriesBlue == 65535);
+        OFCHECK(numEntriesGreen == 65535);
+        OFCHECK(redData != NULL);
+        OFCHECK(greenData != NULL);
+        OFCHECK(blueData != NULL);
+        if (redData && greenData && blueData)
+        {
+            for (Uint32 i = 0; i < 65535; i++)
+            {
+                OFCHECK(redData[i] == i);
+                OFCHECK(greenData[i] == i);
+                OFCHECK(blueData[i] == i);
+            }
+        }
+    }
+}
+
diff --git a/dcmseg/tests/tpacking.cc b/dcmseg/tests/tpacking.cc
new file mode 100644 (file)
index 0000000..abde629
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmseg
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Test for packing and unpacking binary segmentation pixel data
+ *
+ */
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+
+#include "dcmtk/dcmseg/segdoc.h"
+#include "dcmtk/dcmseg/segment.h"
+#include "dcmtk/dcmseg/segutils.h"
+#include "dcmtk/ofstd/oftest.h"
+
+#include "dcmtk/dcmfg/fgfracon.h"
+#include "dcmtk/dcmfg/fgpixmsr.h"
+#include "dcmtk/dcmfg/fgplanor.h"
+#include "dcmtk/dcmfg/fgplanpo.h"
+#include "dcmtk/dcmfg/fgseg.h"
+#include "dcmtk/dcmiod/iodmacro.h"
+#include "dcmtk/dcmdata/dcxfer.h"
+#include "dcmtk/dcmdata/dcdict.h"
+#include "dcmtk/ofstd/ofmem.h"
+#include "dcmtk/ofstd/oftempf.h"
+#include "dcmtk/ofstd/oftest.h"
+//#include <iostream>
+
+static const Uint16 NUM_ROWS             = 512;
+static const Uint16 NUM_COLS             = 512;
+// 17388
+static const Uint16 NUM_FRAMES           = 17000;
+static const size_t NUM_PIXELS_PER_FRAME = NUM_COLS * NUM_ROWS;
+
+static OFString EXPECTED_DUMP;
+
+static void prepareExpectedDump();
+static DcmSegmentation* create();
+static void setGenericValues(DcmSegmentation* seg);
+static void addSharedFGs(DcmSegmentation* seg);
+static void addFrames(DcmSegmentation* seg);
+static void addDimensions(DcmSegmentation* seg);
+static OFString write(DcmSegmentation* seg, DcmDataset& ds);
+
+OFTEST(dcmseg_packing)
+{
+    // Make sure data dictionary is loaded
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK_FAIL("no data dictionary loaded, check environment variable: " DCM_DICT_ENVIRONMENT_VARIABLE);
+        return;
+    }
+
+    // Creation
+    std::cout << "Creating segmentation" << std::endl;
+    DcmSegmentation* seg = create();
+    std::cout << "Setting generic values" << std::endl;
+    setGenericValues(seg);
+    std::cout << "Adding shared functional groups" << std::endl;
+    addSharedFGs(seg);
+    std::cout << "Adding frames" << std::endl;
+    addFrames(seg);
+    std::cout << "Adding dimensions" << std::endl;
+    addDimensions(seg);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+    DcmDataset* ds = dcmff.getDataset();
+
+    // Save to disk, and re-load to test import
+    seg->getFunctionalGroups().setCheckOnWrite(OFFalse);
+    seg->getFunctionalGroups().setUseThreads(16);
+    seg->setCheckDimensionsOnWrite(OFFalse);
+    OFString temp_fn = "/tmp/test.dcm";
+    std::cout << "Writing segmentation to file: " << temp_fn << std::endl;
+    OFCHECK(seg->saveFile(temp_fn.c_str(), EXS_LittleEndianExplicit).good());
+    std::cout << "Temporary file created: " << temp_fn << std::endl;
+    delete seg;
+}
+
+static DcmSegmentation* create()
+{
+    IODGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
+    ContentIdentificationMacro ci("1", "LABEL", "DESCRIPTION", "Doe^John");
+    DcmSegmentation* seg = NULL;
+    OFCondition result;
+    DcmSegmentation::createBinarySegmentation(seg, NUM_ROWS, NUM_COLS , eq, ci);
+    OFCHECK(result.good());
+    OFCHECK(seg != OFnullptr);
+    return seg;
+}
+
+static void setGenericValues(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+    OFCHECK(seg->getPatient().setPatientName("Bond^James").good());
+    OFCHECK(seg->getPatient().setPatientID("007").good());
+    OFCHECK(seg->getPatient().setPatientBirthDate("19771007").good());
+    OFCHECK(seg->getStudy().setStudyDate("20190801").good());
+    OFCHECK(seg->getStudy().setStudyTime("120000").good());
+    OFCHECK(seg->getStudy().setStudyID("1").good());
+    OFCHECK(seg->getPatientStudy().setPatientAge("040Y").good());
+    OFCHECK(seg->getSeries().setSeriesDescription("Test Description").good());
+    OFCHECK(seg->getSeries().setSeriesNumber("1").good());
+    OFCHECK(seg->getSeries().setPatientPosition("HFS").good());
+
+    // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
+    // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
+    // so that they are not overwritten with new, automatically created values later.
+    OFCHECK(seg->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
+    OFCHECK(seg->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
+    OFCHECK(seg->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
+    OFCHECK(seg->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
+    OFCHECK(seg->getGeneralImage().setContentDate("20190927").good());
+    OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
+    OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
+}
+
+
+static void addSharedFGs(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+
+    FGPixelMeasures meas;
+    OFCHECK(meas.setPixelSpacing("0.1\\0.1").good());
+    OFCHECK(meas.setSliceThickness("1.0").good());
+    OFCHECK(meas.setSpacingBetweenSlices("0.05").good());
+
+    FGPlanePosPatient planpo;
+    OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good());
+
+    FGPlaneOrientationPatient planor;
+    OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good());
+
+    OFCHECK(seg->addForAllFrames(meas).good());
+    OFCHECK(seg->addForAllFrames(planpo).good());
+    OFCHECK(seg->addForAllFrames(planor).good());
+}
+
+static void addFrames(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+
+    DcmSegment* segment = NULL;
+    CodeSequenceMacro category("85756007", "SCT", "Tissue");
+    CodeSequenceMacro propType("51114001", "SCT", "Artery");
+
+    OFCHECK(DcmSegment::create(segment, "SEGLABEL", category, propType, DcmSegTypes::SAT_AUTOMATIC, "OC_DUMMY")
+                .good());
+    OFCHECK(segment != OFnullptr);
+    Uint16 forget;
+    OFCHECK(seg->addSegment(segment, forget).good());
+    // Segmentation FG is created automatically
+    FGFrameContent* fg     = new FGFrameContent();
+    OFCHECK(fg);
+    for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++)
+    {
+        fg->setStackID("1");
+
+        OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good());
+        OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good());
+        OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good());
+        OFCHECK(fg->setFrameAcquisitionDuration(0.001).good());
+        OFCHECK(fg->setInStackPositionNumber(frameNo).good());
+        OFCHECK(fg->setDimensionIndexValues(1, 0).good());
+        OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good());
+        OFVector<FGBase*> groups;
+        groups.push_back(fg);
+
+        Uint8* data = new Uint8[NUM_PIXELS_PER_FRAME];
+        for (size_t i = 0; i < NUM_PIXELS_PER_FRAME; ++i)
+        {
+            data[i] = 1;
+        }
+        OFVector<FGBase*> perFrameFGs;
+        perFrameFGs.push_back(fg);
+        OFCHECK(seg->addFrame(data, forget, perFrameFGs).good());
+        delete[] data;
+    }
+    delete fg;
+}
+
+static void addDimensions(DcmSegmentation* seg)
+{
+    if (!seg)
+        return;
+    IODMultiframeDimensionModule& dims = seg->getDimensions();
+    OFCHECK(dims.addDimensionIndex(
+                    DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM")
+                .good());
+    OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber,
+                                   "2.25.30855560781715986879861690673941231222",
+                                   DCM_FrameContentSequence,
+                                   "STACK_DIM")
+                .good());
+    OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org(
+        new IODMultiframeDimensionModule::DimensionOrganizationItem);
+    if (org)
+    {
+        org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222");
+        dims.getDimensionOrganizationSequence().push_back(org.release());
+    }
+}
+
+static OFString write(DcmSegmentation* seg, DcmDataset& ds)
+{
+    OFCondition result = seg->writeDataset(ds);
+    OFCHECK(result.good());
+
+    return "";
+}
index d9df8cebc57eb0d33ef8e86a05300863a7add2c5..97c96e6cc518f8d1be870fe6dcfe35b9fb20fd43 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2024, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -36,6 +36,7 @@
 #include "dcmtk/ofstd/ofmem.h"
 #include "dcmtk/ofstd/oftempf.h"
 #include "dcmtk/ofstd/oftest.h"
+//#include <iostream>
 
 static const Uint8 NUM_ROWS             = 10;
 static const Uint8 NUM_COLS             = 10;
@@ -150,8 +151,10 @@ static void setGenericValues(DcmSegmentation* seg)
     OFCHECK(seg->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
     OFCHECK(seg->getGeneralImage().setContentDate("20190927").good());
     OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
+    OFCHECK(seg->getGeneralImage().setContentTime("153857").good());
 }
 
+
 static void addSharedFGs(DcmSegmentation* seg)
 {
     if (!seg)
@@ -178,9 +181,9 @@ static void addFrames(DcmSegmentation* seg)
     if (!seg)
         return;
 
-    FGSegmentation* fg_seg = new FGSegmentation();
+    // Segmentation FG is created automatically
     FGFrameContent* fg     = new FGFrameContent();
-    OFCHECK(fg && fg_seg);
+    OFCHECK(fg);
     fg->setStackID("1");
     if (fg)
     {
@@ -209,16 +212,13 @@ static void addFrames(DcmSegmentation* seg)
             {
                 data[i] = i;
             }
-            OFCHECK(fg_seg->setReferencedSegmentNumber(frameNo).good());
             OFVector<FGBase*> perFrameFGs;
             perFrameFGs.push_back(fg);
-            perFrameFGs.push_back(fg_seg);
-            OFCHECK(seg->addFrame(data, frameNo, perFrameFGs).good());
+            OFCHECK(seg->addFrame<Uint8>(data, frameNo, perFrameFGs).good());
             delete[] data;
         }
     }
     delete fg;
-    delete fg_seg;
 }
 
 static void addDimensions(DcmSegmentation* seg)
@@ -354,13 +354,13 @@ static void checkConcatenationInstance(size_t numInstance, DcmSegmentation* srcI
     OFCHECK(fg != NULL);
     OFCHECK(perFrame == OFFalse);
 
-    const DcmIODTypes::Frame* frame = concat->getFrame(0);
+    const DcmIODTypes::Frame<Uint8>* frame = OFstatic_cast(const DcmIODTypes::Frame<Uint8>*, concat->getFrame(0));
     OFCHECK(frame != OFnullptr);
-    OFCHECK(frame->pixData != OFnullptr);
-    OFCHECK(OFstatic_cast(Uint8, frame->length) == NUM_PIXELS_PER_FRAME);
-    for (size_t pix = 0; pix < frame->length; pix++)
+    OFCHECK(frame->m_pixData != OFnullptr);
+    OFCHECK(OFstatic_cast(Uint8, frame->getLengthInBytes()) == NUM_PIXELS_PER_FRAME);
+    for (size_t pix = 0; pix < frame->getLengthInBytes(); pix++)
     {
-        OFCHECK(frame->pixData[pix] == pix);
+        OFCHECK(frame->m_pixData[pix] == pix);
     }
     delete concat;
 }
@@ -719,6 +719,7 @@ static void prepareExpectedDump()
     EXPECTED_DUMP += "(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem\n";
     EXPECTED_DUMP += "(0062,000e) US 255                                      #   2, 1 MaximumFractionalValue\n";
     EXPECTED_DUMP += "(0062,0010) CS [OCCUPANCY]                              #  10, 1 SegmentationFractionalType\n";
+    EXPECTED_DUMP += "(0062,0013) CS [UNDEFINED]                              #  10, 1 SegmentsOverlap\n";
     EXPECTED_DUMP += "(0070,0080) CS [LABEL]                                  #   6, 1 ContentLabel\n";
     EXPECTED_DUMP += "(0070,0081) LO [DESCRIPTION]                            #  12, 1 ContentDescription\n";
     EXPECTED_DUMP += "(0070,0084) PN [Doe^John]                               #   8, 1 ContentCreatorName\n";
index 37405859fc65481756c7772b6b27ac26594ce01a..03217aac76e8ee86045585bf665cf3a856e7fe28 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2024, OFFIS e.V.
+ *  Copyright (C) 2015-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
 
-#include "dcmtk/dcmiod/iodtypes.h"
 #include "dcmtk/dcmseg/segutils.h"
+#include "dcmtk/dcmseg/segtypes.h"
 #include "dcmtk/ofstd/oftest.h"
 #include "dcmtk/ofstd/ofstd.h"
+#include "dcmtk/ofstd/oftime.h" // For debugByte2Bin
+#include <iostream>
 
 #define bufLen 4
 
 // Check whether packing of sparse frames into binary packed frames works correctly
 OFTEST(dcmseg_packBinaryFrame)
 {
-
     // Check whether the following statically defined frames are packed correctly
     Uint8 sparseFrame1[8] = {1, 1, 1, 1, 0, 0, 0, 0};
-    DcmIODTypes::Frame* packed = DcmSegUtils::packBinaryFrame(sparseFrame1, 4, 2);
+    DcmIODTypes::Frame<Uint8>* packed = DcmSegUtils::packBinaryFrame(sparseFrame1, 4, 2);
     OFCHECK(packed != NULL);
-    OFCHECK(packed->length == 1);
-    OFCHECK_MSG(packed->pixData[0] == 0b00001111, OFString("Expected 0b00001111, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[0]));
+    OFCHECK(packed->getLengthInBytes() == 1);
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[0] == 0b00001111, OFString("Expected 0b00001111, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[0]));
     delete packed;
 
     Uint8 sparseFrame2[8] = {1, 0, 1, 0, 1, 0, 1, 0};
     packed = DcmSegUtils::packBinaryFrame(sparseFrame2, 4, 2);
     OFCHECK(packed != NULL);
-    OFCHECK(packed->length == 1);
-    OFCHECK_MSG(packed->pixData[0] == 0b01010101, OFString("Expected 0b01010101, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[0]));
+    OFCHECK(packed->getLengthInBytes() == 1);
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[0] == 0b01010101, OFString("Expected 0b01010101, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[0]));
     delete packed;
 
     // Now try the that is larger than a byte and not a multiple of 8, with every third pixel set to 1
     Uint8 sparseFrame3[15] = {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1};
     packed = DcmSegUtils::packBinaryFrame(sparseFrame3, 5, 3);
     OFCHECK(packed != NULL);
-    OFCHECK(packed->length == 2);
-    OFCHECK_MSG(packed->pixData[0] == 0b00100100, OFString("Expected 0b00100100, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[0]));
-    OFCHECK_MSG(packed->pixData[1] == 0b01001001, OFString("Expected 0b01001001, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[1]));
+    OFCHECK(packed->getLengthInBytes() == 2);
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[0] == 0b00100100, OFString("Expected 0b00100100, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[0]));
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[1] == 0b01001001, OFString("Expected 0b01001001, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[1]));
     delete packed;
 
     // Now the same but with every 5th pixel set to 1, and rows=7 and cols=5
@@ -66,21 +67,23 @@ OFTEST(dcmseg_packBinaryFrame)
     }
     packed = DcmSegUtils::packBinaryFrame(sparseFrame4, 7, 5);
     OFCHECK(packed != NULL);
-    OFCHECK(packed->length == 5);
-    OFCHECK_MSG(packed->pixData[0] == 0b00100001, OFString("Expected 0b00100001, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[0]));
-    OFCHECK_MSG(packed->pixData[1] == 0b10000100, OFString("Expected 0b10000100, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[1]));
-    OFCHECK_MSG(packed->pixData[2] == 0b00010000, OFString("Expected 0b00010000, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[2]));
-    OFCHECK_MSG(packed->pixData[3] == 0b01000010, OFString("Expected 0b01000010, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[3]));
-    OFCHECK_MSG(packed->pixData[4] == 0b00000000, OFString("Expected 0b00000000, got ") + DcmSegUtils::debugByte2Bin(packed->pixData[4]));
+    OFCHECK(packed->getLengthInBytes() == 5);
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[0] == 0b00100001, OFString("Expected 0b00100001, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[0]));
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[1] == 0b10000100, OFString("Expected 0b10000100, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[1]));
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[2] == 0b00010000, OFString("Expected 0b00010000, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[2]));
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[3] == 0b01000010, OFString("Expected 0b01000010, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[3]));
+    OFCHECK_MSG(OFstatic_cast(Uint8*, packed->getPixelData())[4] == 0b00000000, OFString("Expected 0b00000000, got ") + DcmSegUtils::debugByte2Bin(  OFstatic_cast(Uint8*, packed->getPixelData())[4]));
+    delete packed;
 
     // In 1000 iterations create sparse frames and pack them. Check whether the
     // packed frame is correct. This is not bullet proof but we use the same addressing
-    // as in the packing/unpacking code to make sure we address the right bit.
+    // as in the packing/unpacking code to make sure we address the correct bit.
     // Use a random number of cols and rows (each between 1 and 100).
     // If the packed frame is not correct, the test fails.
-    unsigned int now = OFstatic_cast(unsigned int, time(NULL));
+    OFTime tm;
     for (unsigned int i = 0; i < 1000; i++)
     {
+        unsigned int now = OFstatic_cast(unsigned int, time(NULL));
         Uint16 cols = OFrand_r(now) % 100 + 1;
         Uint16 rows = OFrand_r(now) % 100 + 1;
         Uint16 pixelCount = cols * rows;
@@ -91,11 +94,12 @@ OFTEST(dcmseg_packBinaryFrame)
         // Create a random sparse frame
         for (unsigned int j = 0; j < pixelCount; j++)
         {
-            sparseFrame[j] =  OFrand_r(now) % 2;
+            tm.setCurrentTime();
+            unsigned int micro = tm.getMicroSecond();
+            sparseFrame[j] =  OFrand_r(micro) % 2;
         }
-
         // Pack the frame
-        DcmIODTypes::Frame* packedFrame = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
+        DcmIODTypes::Frame<Uint8>* packedFrame = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
         OFCHECK(packedFrame != NULL);
 
         // Check the result
@@ -104,12 +108,15 @@ OFTEST(dcmseg_packBinaryFrame)
             Uint32 byteIndex = j / 8;
             Uint32 bitIndex = j % 8;
             Uint8 mask = 1 << bitIndex;
-            if ((sparseFrame[j] != 0) != ((packedFrame->pixData[byteIndex] & mask) != 0))
+            Uint8 currentByte = OFstatic_cast(Uint8*, packedFrame->getPixelData())[byteIndex];
+            // Check whether the bit at position j is set correctly
+            if ((sparseFrame[j] == 0) != ((currentByte & mask) == 0))
             {
                 OFCHECK_FAIL("Failed for row " << j / cols << " and column " << j % cols);
             }
         }
 
+        // Clean up
         delete[] sparseFrame;
         delete packedFrame;
     }
@@ -130,8 +137,8 @@ OFTEST(dcmseg_packAndUnpackBinaryFrame)
 
         Uint8* sparseFrame = new Uint8[pixelCount];
         OFCHECK(sparseFrame != NULL);
-        DcmIODTypes::Frame* packed;
-        DcmIODTypes::Frame* unpacked;
+        DcmIODTypes::FrameBase* packed;
+        DcmIODTypes::FrameBase* unpacked;
 
         // Create a random sparse frame
         for (unsigned int j = 0; j < pixelCount; j++)
@@ -142,11 +149,11 @@ OFTEST(dcmseg_packAndUnpackBinaryFrame)
         // Pack and unpack the frame
         packed = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
         OFCHECK(packed != NULL);
-        unpacked = DcmSegUtils::unpackBinaryFrame(packed, rows, cols);
+        unpacked = DcmSegUtils::unpackBinaryFrame(OFstatic_cast(DcmIODTypes::Frame<Uint8>*, packed), rows, cols);
         OFCHECK(unpacked != NULL);
 
         // Compare the result
-        OFCHECK(memcmp(sparseFrame, unpacked->pixData, pixelCount) == 0);
+        OFCHECK(memcmp(sparseFrame, unpacked->getPixelData(), pixelCount) == 0);
 
         delete[] sparseFrame;
         delete packed;
@@ -162,20 +169,20 @@ OFTEST(dcmseg_packAndUnpackBinaryFrame)
         Uint8* sparseFrame = new Uint8[pixelCount];
         OFCHECK(sparseFrame != NULL);
         memset(sparseFrame, 0, pixelCount);
-        DcmIODTypes::Frame* packed = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
+        DcmIODTypes::FrameBase* packed = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
         OFCHECK(packed != NULL);
-        DcmIODTypes::Frame* unpacked = DcmSegUtils::unpackBinaryFrame(packed, rows, cols);
+        DcmIODTypes::FrameBase* unpacked = DcmSegUtils::unpackBinaryFrame(OFstatic_cast(DcmIODTypes::Frame<Uint8>*, packed), rows, cols);
         OFCHECK(unpacked != NULL);
-        OFCHECK(memcmp(sparseFrame, unpacked->pixData, pixelCount) == 0);
+        OFCHECK(memcmp(sparseFrame, unpacked->getPixelData(), pixelCount) == 0);
         delete packed;
         delete unpacked;
 
         memset(sparseFrame, 1, pixelCount);
         packed = DcmSegUtils::packBinaryFrame(sparseFrame, rows, cols);
         OFCHECK(packed != NULL);
-        unpacked = DcmSegUtils::unpackBinaryFrame(packed, rows, cols);
+        unpacked = DcmSegUtils::unpackBinaryFrame(OFstatic_cast(DcmIODTypes::Frame<Uint8>*, packed), rows, cols);
         OFCHECK(unpacked != NULL);
-        OFCHECK(memcmp(sparseFrame, unpacked->pixData, pixelCount) == 0);
+        OFCHECK(memcmp(sparseFrame, unpacked->getPixelData(), pixelCount) == 0);
         delete packed;
         delete unpacked;
 
@@ -190,11 +197,11 @@ OFTEST(dcmseg_concatBinaryFrames)
     const int cols = 4;
     Uint8 sparseFrame1[rows * cols] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
     Uint8 sparseFrame2[rows * cols] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
-    DcmIODTypes::Frame* packed1 = DcmSegUtils::packBinaryFrame(sparseFrame1, rows, cols);
-    DcmIODTypes::Frame* packed2 = DcmSegUtils::packBinaryFrame(sparseFrame2, rows, cols);
+    DcmIODTypes::FrameBase* packed1 = DcmSegUtils::packBinaryFrame(sparseFrame1, rows, cols);
+    DcmIODTypes::FrameBase* packed2 = DcmSegUtils::packBinaryFrame(sparseFrame2, rows, cols);
     OFCHECK(packed1 != NULL);
     OFCHECK(packed2 != NULL);
-    OFVector<DcmIODTypes::Frame*> inputFrames;
+    OFVector<DcmIODTypes::FrameBase*> inputFrames;
     inputFrames.push_back(packed1);
     inputFrames.push_back(packed2);
     // Now concatenate the two frames into a single bit array
@@ -206,6 +213,10 @@ OFTEST(dcmseg_concatBinaryFrames)
     OFCHECK_MSG(pixData[0] == 0b11111111, OFString("Expected 0b11111111, got ") + DcmSegUtils::debugByte2Bin(pixData[0]));
     OFCHECK_MSG(pixData[1] == 0b11101111, OFString("Expected 0b11101111, got ") + DcmSegUtils::debugByte2Bin(pixData[1]));
     OFCHECK_MSG(pixData[2] == 0b11111111, OFString("Expected 0b11111111, got ") + DcmSegUtils::debugByte2Bin(pixData[2]));
+    // avoid memory leaks
+    delete packed1;
+    delete packed2;
+    delete[] pixData;
 }
 
 // Test DcmSegUtils::debugByte2Bin()
index 998ecb38818e09592ed3056361851352815a7f0c..4ca506c21611e113b53279e1e762972a6be4ebac 100644 (file)
@@ -582,6 +582,6 @@ It is an error if no data dictionary can be loaded.
 
 \section dcmsign_copyright COPYRIGHT
 
-Copyright (C) 2000-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2000-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 242f5128f380d54e0d23882213d91d253c2dafad..c80e718cca835b8301885e0e930f1f17fa7d942c 100644 (file)
@@ -86,8 +86,9 @@ dsr2html.o: dsr2html.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -116,7 +117,6 @@ dsr2html.o: dsr2html.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixseq.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcofsetl.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrae.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrur.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
@@ -231,8 +231,9 @@ dsr2xml.o: dsr2xml.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -261,7 +262,6 @@ dsr2xml.o: dsr2xml.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixseq.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcofsetl.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrae.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrur.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
@@ -376,8 +376,9 @@ dsrdump.o: dsrdump.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -406,7 +407,6 @@ dsrdump.o: dsrdump.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixseq.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcofsetl.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrae.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrur.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
@@ -521,8 +521,9 @@ xml2dsr.o: xml2dsr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -551,7 +552,6 @@ xml2dsr.o: xml2dsr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixseq.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcofsetl.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrae.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrur.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
index 469611ed97ead25728ba3727177601e68f70792c..a1b765412200525033c4e963dc5850f2c148a7fa 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -207,7 +207,9 @@ int main(int argc, char *argv[])
     E_FileReadMode opt_readMode = ERM_autoDetect;
     E_TransferSyntax opt_ixfer = EXS_Unknown;
     OFBool opt_checkAllStrings = OFFalse;
+#ifdef DCMTK_ENABLE_CHARSET_CONVERSION
     OFBool opt_convertToUTF8 = OFFalse;
+#endif
 
     OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION, "Render DICOM SR file and data set to HTML/XHTML", rcsid);
     OFCommandLine cmd;
index e20368208aeb4eb008e12331d594ad3ca740be0a..590b3c210eb80373ac5261b9af3f3600902da01c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2023, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
index 054e58d4df714f53c7277ddc450c56e6719d1960..c4309b550cf0995a041e74bbbe430df40f33a73d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2003-2024, OFFIS e.V.
+ *  Copyright (C) 2003-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -30,6 +30,7 @@
 
 #include "dcmtk/ofstd/ofstream.h"
 #include "dcmtk/ofstd/ofconapp.h"
+#include "dcmtk/ofstd/ofdiag.h"
 
 #ifdef WITH_ZLIB
 #include <zlib.h>                     /* for zlibVersion() */
@@ -56,8 +57,12 @@ static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
 #define LIBXML_ATTR_FORMAT(fmt,args)
 #endif
 
+// MacOS 15.5 defines some Clang specific pragmas in libxml header files.
+// Suppress warnings caused by these pragmas when compiling with GCC.
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC
 #include <libxml/parser.h>
-
+#include DCMTK_DIAGNOSTIC_POP
 
 #define SHORTCOL 3
 #define LONGCOL 21
index 7230eb2e09672e10aef150bb6034c5beac7447cb..b24f28b1bcd6d6b6b95ff1d5800994c2d324fddc 100644 (file)
@@ -10,7 +10,7 @@
   <xsd:annotation>
     <xsd:documentation xml:lang="en">
       XML Schema for DCMTK tools dsr2xml and xml2dsr.
-      Copyright (C) 2003-2024, OFFIS e.V. and J. Riesmeier
+      Copyright (C) 2003-2025, OFFIS e.V. and J. Riesmeier
       All rights reserved.  See COPYRIGHT file for details.
     </xsd:documentation>
   </xsd:annotation>
@@ -91,7 +91,8 @@
         </xsd:complexType>
       </xsd:element>
       <xsd:element name="sex" type="dsr:Sex" minOccurs="0"/>
-      <!-- strictly speaking, Patient's Size and Weight belong to the Study IE -->
+      <!-- strictly speaking, Patient's Age, Size and Weight belong to the Study IE -->
+      <xsd:element name="age" type="dsr:AgeString" minOccurs="0"/>
       <xsd:element name="size" type="dsr:DecimalString" minOccurs="0"/>
       <xsd:element name="weight" type="dsr:DecimalString" minOccurs="0"/>
     </xsd:sequence>
     </xsd:restriction>
   </xsd:simpleType>
 
+  <xsd:simpleType name="AgeString">
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[0-9]{3}[DWMY]"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
   <xsd:complexType name="PersonName">
     <!-- minLength? -->
     <xsd:sequence>
index fe3bdd48f640cae356a621c2d5ade82f6b0f662c..adef1e2535091be07a1c7adfd26b279825854791 100644 (file)
@@ -257,8 +257,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 \endverbatim
 
+(*) This is not a Storage SOP Class, but used for Real-Time Communication.
+
 \subsection dsr2html_character_encoding Character Encoding
 
 The HTML/XHTML encoding is determined automatically from the DICOM attribute
@@ -296,6 +300,14 @@ hebrew.
 Option \e --convert-to-utf8 can be used to convert the DICOM file or data set
 to UTF-8 encoding prior to the rendering to HTML/XHTML format.
 
+\subsection dsr2html_security Security
+
+Please note that using one of the options \e --css-reference, \e --css-file or
+\e --hyperlink-url-prefix can lead to security issues, as an attacker could
+misuse them to potentially inject dangerous content into the HTML/XHTML output.
+The values passed to these options are not checked, neither the URL and prefix
+nor the content of the specified CSS file.
+
 \section dsr2html_logging LOGGING
 
 The level of logging output of the various command line tools and underlying
@@ -366,7 +378,7 @@ replace any built-in tables.
 \section dsr2html_files FILES
 
 <em>\<datadir\>/report.css</em> - Sample Cascading Stylesheet file for HTML
-<em>\<datadir\>/reportx.css</em> - Sample Cascading Stylesheet file for XHTML
+\n<em>\<datadir\>/reportx.css</em> - Sample Cascading Stylesheet file for XHTML
 
 \section dsr2html_see_also SEE ALSO
 
@@ -374,6 +386,6 @@ replace any built-in tables.
 
 \section dsr2html_copyright COPYRIGHT
 
-Copyright (C) 2000-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2000-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 35a65e7a0e157b6131edd8cfbc903d1cfe5257da..a24cb4260b8653f3c3a53b1736a1a0a8d9aaf77d 100644 (file)
@@ -220,8 +220,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 \endverbatim
 
+(*) This is not a Storage SOP Class, but used for Real-Time Communication.
+
 Please note that currently only mandatory and some optional attributes are
 supported.
 
@@ -359,6 +363,6 @@ replace any built-in tables.
 
 \section dsr2xml_copyright COPYRIGHT
 
-Copyright (C) 2000-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2000-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index a15e3464483e8726ca808405278f6831050fbb3b..067343957ea2c38aac66dbdf6388641b6348802a 100644 (file)
@@ -226,8 +226,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 \endverbatim
 
+(*) This is not a Storage SOP Class, but used for Real-Time Communication.
+
 \section dsrdump_logging LOGGING
 
 The level of logging output of the various command line tools and underlying
@@ -301,6 +305,6 @@ replace any built-in tables.
 
 \section dsrdump_copyright COPYRIGHT
 
-Copyright (C) 2000-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2000-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 60dd451bfdc45b837e7640623e409968b05946bf..6a0cea289deda0bc030e281de5fe345d07b0aa65 100644 (file)
@@ -194,8 +194,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 \endverbatim
 
+(*) This is not a Storage SOP Class, but used for Real-Time Communication.
+
 Please note that currently only mandatory and some optional attributes are
 supported.
 
@@ -312,6 +316,6 @@ It is an error if no data dictionary can be loaded.
 
 \section xml2dsr_copyright COPYRIGHT
 
-Copyright (C) 2003-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 2003-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 560b3493782aefb5d98bdf69434366c0894018ef..f4bc85caa36d71448b6329fb39596cd914e3e75d 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID100_QuantitativeDiagnosticImagingProcedure
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:09 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:43 by J. Riesmeier
  *
  */
 
@@ -28,7 +28,7 @@
 
 /** Implementation of DCMR Context Group:
  *  CID 100 - Quantitative Diagnostic Imaging Procedure.
- *  (type: extensible, version: 20230630)
+ *  (type: extensible, version: 20250122)
  */
 class DCMTK_CMR_EXPORT CID100_QuantitativeDiagnosticImagingProcedure
   : public DSRContextGroup
@@ -75,9 +75,7 @@ class DCMTK_CMR_EXPORT CID100_QuantitativeDiagnosticImagingProcedure
         /// (39142-5,LN,"CT perfusion head with contrast IV")
         CTPerfusionHeadWithContrastIV,
         /// (39632-5,LN,"SPECT brain")
-        SPECTBrain,
-        /// (RPID5427,RADLEX,"NM head perfusion brain PET-CT AV-45")
-        NMHeadPerfusionBrainPET_CT_AV45
+        SPECTBrain
     };
 
     /** (default) constructor
index 928cafa43b1e648c4a7bb99645359941a3552bec..5b268dd5cd4f424fbcd487090b6dfe8cd52c5c5b 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID10013_CTAcquisitionType
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:25 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:57 by J. Riesmeier
  *
  */
 
index 2e87fa4dc1b0b855ddd215191495003e3d963464..b133a73ce046c09a0cdbefff153ba5cdcc8b2974 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID10033_CTReconstructionAlgorithm
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:26 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:58 by J. Riesmeier
  *
  */
 
index d222daef0b8034e27ddf80584e4cf66180650683..b5599edbf4fdd38aa946561d61930382d36bb801 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID11_AdministrationRoute
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:06 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:40 by J. Riesmeier
  *
  */
 
index 65bf319658037761eddcc5d50026d589d6a41222..63b92a616b419109d3e05fd432fd59928b03528a 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID218_QuantitativeImageFeature
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:10 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:44 by J. Riesmeier
  *
  */
 
index cb38c10785742c757eab01aa674415fba5fd091f..e02bb87e8bc5a3ff56de26269b3c9076e48bff7f 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID244_Laterality
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:11 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:45 by J. Riesmeier
  *
  */
 
index de4afe1dfaa0794ba2e2546e519886ff5812cb4a..aa912612b01fc1ac7d83205c60e10713155dac66 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID247_LateralityLeftRightOnly
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:12 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:45 by J. Riesmeier
  *
  */
 
index a9666a8d7a7b92914222f565f29519abdcbb3379..a51f95f52a51e68047bf6ec8fc5cb46c95f07707 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID29_AcquisitionModality
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:07 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:41 by J. Riesmeier
  *
  */
 
@@ -72,8 +72,8 @@ class DCMTK_CMR_EXPORT CID29_AcquisitionModality
         IntravascularUltrasound,
         /// (KER,DCM,"Keratometry")
         Keratometry,
-        /// (LS,DCM,"Laser Scan")
-        LaserScan,
+        /// (LS,DCM,"Laser surface scan")
+        LaserSurfaceScan,
         /// (LEN,DCM,"Lensometry")
         Lensometry,
         /// (MR,DCM,"Magnetic Resonance")
index 75f9b16323ee23c3d294bdac033027f0b0a41dee..ece2202fbd6d5493465d3d1040916a284778ddfb 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID4020_PETRadionuclide
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:13 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:46 by J. Riesmeier
  *
  */
 
index c63f4b5739ac62959aa7bb4c0e7c7f230a2180d9..257f010c3d651cbbf207e3abd0b88d81e0700236 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID4021_PETRadiopharmaceutical
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:14 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:47 by J. Riesmeier
  *
  */
 
@@ -28,7 +28,7 @@
 
 /** Implementation of DCMR Context Group:
  *  CID 4021 - PET Radiopharmaceutical.
- *  (type: extensible, version: 20221201)
+ *  (type: extensible, version: 20251111)
  */
 class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
   : public DSRContextGroup
@@ -44,6 +44,10 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         _28H1_89Zr,
         /// (126713,DCM,"2FA F^18^")
         _2FA_F18,
+        /// (C90936,NCIt,"2-Thymidine C^11^")
+        _2Thymidine_C11,
+        /// (771875003,SCT,"3-N-Methylspiperone C^11^")
+        _3NMethylspiperone_C11,
         /// (126751,DCM,"7D12 ^89^Zr")
         _7D12_89Zr,
         /// (126750,DCM,"7E11 ^89^Zr")
@@ -96,10 +100,10 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         CMAbU36_89Zr,
         /// (126515,DCM,"cU36 ^89^Zr")
         CU36_89Zr,
+        /// (C412822,MSH,"DASB C^11^")
+        DASB_C11,
         /// (C96234,NCIt,"DCFBC F^18^")
         DCFBC_F18,
-        /// (C116352,NCIt,"Piflufolastat F^18^")
-        Piflufolastat_F18,
         /// (126762,DCM,"Df-[FK](2) ^89^Zr")
         DfFK2_89Zr,
         /// (126763,DCM,"Df-[FK](2)-3PEG(4) ^89^Zr")
@@ -112,6 +116,8 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         DfFKPEG3_89Zr,
         /// (126747,DCM,"DN30 ^89^Zr")
         DN30_89Zr,
+        /// (724025002,SCT,"Dotatate Ga^68^")
+        Dotatate_Ga68,
         /// (126765,DCM,"DPA-713 ^11^C")
         DPA713_11C,
         /// (126766,DCM,"DPA-714 ^18^F")
@@ -148,6 +154,8 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         Flumazenil_F18,
         /// (424708001,SCT,"Fluorethyltyrosin F^18^")
         Fluorethyltyrosin_F18,
+        /// (C62520,NCIt,"Fluoroazomycin arabinoside F^18^")
+        FluoroazomycinArabinoside_F18,
         /// (423546004,SCT,"Fluorobenzothiazole F^18^")
         Fluorobenzothiazole_F18,
         /// (456992002,SCT,"Fluorocholine F^18^")
@@ -166,6 +174,8 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         Fluoromisonidazole_F18,
         /// (C2934038,UMLS,"Fluoropropyl-dihydrotetrabenazine F^18^")
         FluoropropylDihydrotetrabenazine_F18,
+        /// (764937002,SCT,"Fluorothymidine F^18^")
+        Fluorothymidine_F18,
         /// (126707,DCM,"Fluorotriopride F^18^")
         Fluorotriopride_F18,
         /// (425236000,SCT,"Fluorouracil F^18^")
@@ -182,6 +192,8 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         Germanium_Ge68,
         /// (126724,DCM,"Glembatumumab vedotin ^89^Zr")
         GlembatumumabVedotin_89Zr,
+        /// (126521,DCM,"Glucose C^11^")
+        Glucose_C11,
         /// (129509006,SCT,"Glutamate N^13^")
         Glutamate_N13,
         /// (126709,DCM,"Glutamine C^11^")
@@ -230,6 +242,12 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         Panitumumab_89Zr,
         /// (126728,DCM,"Pegdinetanib ^89^Zr")
         Pegdinetanib_89Zr,
+        /// (C148167,NCIt,"Pembrolizumab ^89^Zr")
+        Pembrolizumab_89Zr,
+        /// (C5433257,UMLS,"PI-2620 F^18^")
+        PI2620_F18,
+        /// (C116352,NCIt,"Piflufolastat F^18^")
+        Piflufolastat_F18,
         /// (126725,DCM,"Pinatuzumab vedotin ^89^Zr")
         PinatuzumabVedotin_89Zr,
         /// (126500,DCM,"Pittsburgh compound B C^11^")
@@ -286,14 +304,10 @@ class DCMTK_CMR_EXPORT CID4021_PETRadiopharmaceutical
         THK5317_F18,
         /// (C4279748,UMLS,"THK5351 F^18^")
         THK5351_F18,
-        /// (129502002,SCT,"Thymidine F^18^")
-        Thymidine_F18,
         /// (126512,DCM,"Trastuzumab ^89^Zr")
         Trastuzumab_89Zr,
         /// (126749,DCM,"TRC105 ^89^Zr")
         TRC105_89Zr,
-        /// (724025002,SCT,"Dotatate Ga^68^")
-        Dotatate_Ga68,
         /// (126739,DCM,"Ublituximab ^89^Zr")
         Ublituximab_89Zr,
         /// (C4506788,UMLS,"UCB-J C^11^")
index 6ae882a79e9f5ef79c03c3c56d592355e3fe112d..513aca4ba602b36baa2cd7f2ac95e92542d05d01 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID4031_CommonAnatomicRegion
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:15 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:48 by J. Riesmeier
  *
  */
 
@@ -28,7 +28,7 @@
 
 /** Implementation of DCMR Context Group:
  *  CID 4031 - Common Anatomic Region.
- *  (type: extensible, version: 20221224)
+ *  (type: extensible, version: 20250709)
  */
 class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
   : public DSRContextGroup
@@ -68,16 +68,18 @@ class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
         Bronchus,
         /// (80144004,SCT,"Calcaneus")
         Calcaneus,
+        /// (113257007,SCT,"Cardiovascular system")
+        CardiovascularSystem,
         /// (122494005,SCT,"Cervical spine")
         CervicalSpine,
         /// (1217257000,SCT,"Cervico-thoracic spine")
         CervicoThoracicSpine,
         /// (816094009,SCT,"Chest")
         Chest,
-        /// (416550000,SCT,"Chest and Abdomen")
-        ChestAndAbdomen,
         /// (416775004,SCT,"Chest, Abdomen and Pelvis")
         ChestAbdomenAndPelvis,
+        /// (416550000,SCT,"Chest and Abdomen")
+        ChestAndAbdomen,
         /// (51299004,SCT,"Clavicle")
         Clavicle,
         /// (64688005,SCT,"Coccyx")
@@ -152,6 +154,8 @@ class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
         LowerLeg,
         /// (61685007,SCT,"Lower limb")
         LowerLimb,
+        /// (63337009,SCT,"Lower trunk")
+        LowerTrunk,
         /// (122496007,SCT,"Lumbar spine")
         LumbarSpine,
         /// (1217253001,SCT,"Lumbo-sacral spine")
@@ -172,12 +176,12 @@ class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
         NasalBone,
         /// (45048000,SCT,"Neck")
         Neck,
-        /// (417437006,SCT,"Neck and Chest")
-        NeckAndChest,
-        /// (416152001,SCT,"Neck, Chest and Abdomen")
-        NeckChestAndAbdomen,
         /// (416319003,SCT,"Neck, Chest, Abdomen and Pelvis")
         NeckChestAbdomenAndPelvis,
+        /// (416152001,SCT,"Neck, Chest and Abdomen")
+        NeckChestAndAbdomen,
+        /// (417437006,SCT,"Neck and Chest")
+        NeckAndChest,
         /// (55024004,SCT,"Optic canal")
         OpticCanal,
         /// (363654007,SCT,"Orbital structure")
@@ -226,6 +230,8 @@ class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
         SmallIntestine,
         /// (421060004,SCT,"Spine")
         Spine,
+        /// (737561001,SCT,"Spine and/or cord")
+        SpineAndPerOrCord,
         /// (7844006,SCT,"Sternoclavicular joint")
         SternoclavicularJoint,
         /// (56873002,SCT,"Sternum")
@@ -250,10 +256,14 @@ class DCMTK_CMR_EXPORT CID4031_CommonAnatomicRegion
         Toe,
         /// (44567001,SCT,"Trachea")
         Trachea,
+        /// (22943007,SCT,"Trunk")
+        Trunk,
         /// (40983000,SCT,"Upper arm")
         UpperArm,
         /// (53120007,SCT,"Upper limb")
         UpperLimb,
+        /// (67734004,SCT,"Upper trunk")
+        UpperTrunk,
         /// (431491007,SCT,"Upper urinary tract")
         UpperUrinaryTract,
         /// (87953007,SCT,"Ureter")
index 180d1dd7cb80688af49348032d0a3b67e06ec18d..6ca7ff0341cc8e8de122cd18318887349ab6f205 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID42_NumericValueQualifier
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:08 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:42 by J. Riesmeier
  *
  */
 
index f4265699913d547df618509cbc8e8cb49240d5d1..08531b1395f88d95359ad98a0920b25eab545170 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID6147_ResponseCriteria
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:16 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:49 by J. Riesmeier
  *
  */
 
index 749b42f8211567be1d5dc0f78c726abf35d51fdf..e839ed008269053548f43ebd9d30ab823263a069 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7021_MeasurementReportDocumentTitle
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:17 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:50 by J. Riesmeier
  *
  */
 
index 2d3f50fb7aabf1f5a423868aa615e53ffd532405..04a6bb24c8230e290d0d29adbc9bcfd255c125dc 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7181_AbstractMultiDimensionalImageModelComponentUnit
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:18 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:51 by J. Riesmeier
  *
  */
 
index b2b40d18e2238cbe0049f924d5d252ddc0755d2c..b0f196ae746dd881e6abd61de6b0bad34f21714f 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7445_DeviceParticipatingRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:19 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:52 by J. Riesmeier
  *
  */
 
index 5ee59ad07a6ed1bc05d7594a15f04bf187d3ef86..af61d16b8703f35bc328bb8a9be5fd8baf94f695 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7452_OrganizationalRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:20 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:52 by J. Riesmeier
  *
  */
 
index 09227cd29ec33c68e8d03b5b74c215b6df296e6d..2444df5bd496f64995af65073d2454d3146a3e32 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7453_PerformingRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:21 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:53 by J. Riesmeier
  *
  */
 
index 481e4e747ebe36f45cae5097eef6098a9758b122..a21fd7cffbf229d4d87492629e40c583eba81331 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7464_GeneralRegionOfInterestMeasurementModifier
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:22 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:54 by J. Riesmeier
  *
  */
 
index 2b6bc0f6ed136d0925e61201c4c8f717366b9cf4..f01b123fb09200803b2aa137fea3a5459d2e8dce 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7469_GenericIntensityAndSizeMeasurement
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:23 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:55 by J. Riesmeier
  *
  */
 
index eb98b9c324093b49bebd7ef0a44a8877ea929f7c..efb470520622695d63a601569355e9b7388625c3 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:24 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:56 by J. Riesmeier
  *
  */
 
index e34abb8fb340c36ca84abac97c37eede44b0d5e0..5b1bcd398759f3cdfcfa1f47eebcc91a83a83fde 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class TID1500_MeasurementReport
@@ -46,7 +46,7 @@
 
 /** @name specific error conditions for TID 1500 (and included templates) in module dcmsr/cmr
  */
-//@{
+///@{
 
 /// error: there is no measurement report to add content items to
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_NoMeasurementReport;
@@ -57,7 +57,7 @@ extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_InvalidSegmentationObject;
 /// error: the given DICOM object is not a real world value mapping object
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_InvalidRealWorldValueMappingObject;
 
-//@}
+///@}
 
 
 /*---------------------*
index 26702cb155773413caa57e7661e181b44bbd973f..2f7ec8442a7a9a1c087a2b98140890520b45b7a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2017, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2016-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for common error constants used in TID 14xx/15xx
@@ -32,7 +32,7 @@
 
 /** @name specific error conditions for TID 1500 (and included templates) in module dcmsr/cmr
  */
-//@{
+///@{
 
 /// error: there is no measurement report to add content items to
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_NoMeasurementReport;
@@ -45,6 +45,6 @@ extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_InvalidSegmentationObject;
 /// error: the given DICOM object is not a real world value mapping object
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_InvalidRealWorldValueMappingObject;
 
-//@}
+///@}
 
 #endif
index 95d5bfd34fb41b0573d842c06170cac15abfa8cd..a34feb4449e18ac5fc66b28ea65fe8181f9e97a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2021, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file for class TID1600_ImageLibrary
@@ -36,7 +36,7 @@
 
 /** @name specific error conditions for TID 1600 in module dcmsr/cmr
  */
-//@{
+///@{
 
 /// error: there is no image library to add image groups to
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_NoImageLibrary;
@@ -55,7 +55,7 @@ extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_NoImageLibraryEntryDescrip
 /// normal: there are no (common) image library entry descriptors to be moved (to the image group)
 extern DCMTK_CMR_EXPORT const OFConditionConst CMR_EC_NoImageLibraryEntryDescriptorsToBeMoved;
 
-//@}
+///@}
 
 
 /*---------------------*
index 9fbfac2c6edea4a71964eceeaa8c8e4344a5d347..6d2704a42168ce6e9a6e8fc1731abd34c944a5e0 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file with DICOM Controlled Terminology Code Definitions (Coding Scheme "DCM", Version "01")
  *
- *  Generated automatically from DICOM PS 3.16-2024e
- *  File created on 2024-11-16 10:17:26 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 11:52:18 by J. Riesmeier
  *
  */
 
@@ -34,8 +34,8 @@
  *  code definitions  *
  *--------------------*/
 
-// total number of codes: 4861
-// - retired: 207
+// total number of codes: 5092
+// - retired: 208
 // - no name: 27
 // - not unique: 17
 
 #define CODE_DCM_Radiofluoroscopy                                          DSRBasicCodedEntry("RF", "DCM", "Radiofluoroscopy")
 #define CODE_DCM_RadiographicImaging                                       DSRBasicCodedEntry("RG", "DCM", "Radiographic imaging")
 #define CODE_DCM_RadiationTherapyDevice                                    DSRBasicCodedEntry("RT", "DCM", "Radiation Therapy Device")
-#define CODE_DCM_RadiotherapyDose                                          DSRBasicCodedEntry("RTDOSE", "DCM", "Radiotherapy Dose")
-#define CODE_DCM_RadiotherapyImage                                         DSRBasicCodedEntry("RTIMAGE", "DCM", "Radiotherapy Image")
-#define CODE_DCM_RadiotherapyPlan                                          DSRBasicCodedEntry("RTPLAN", "DCM", "Radiotherapy Plan")
-#define CODE_DCM_RadiotherapyTreatmentRecord                               DSRBasicCodedEntry("RTRECORD", "DCM", "Radiotherapy Treatment Record")
-#define CODE_DCM_RadiotherapyStructureSet                                  DSRBasicCodedEntry("RTSTRUCT", "DCM", "Radiotherapy Structure Set")
+#define CODE_DCM_RTDose                                                    DSRBasicCodedEntry("RTDOSE", "DCM", "RT Dose")
+#define CODE_DCM_RTImage                                                   DSRBasicCodedEntry("RTIMAGE", "DCM", "RT Image")
+#define CODE_DCM_RTPlan                                                    DSRBasicCodedEntry("RTPLAN", "DCM", "RT Plan")
+#define CODE_DCM_RTTreatmentRecord                                         DSRBasicCodedEntry("RTRECORD", "DCM", "RT Treatment Record")
+#define CODE_DCM_RTStructureSet                                            DSRBasicCodedEntry("RTSTRUCT", "DCM", "RT Structure Set")
 #define CODE_DCM_RealWorldValueMap                                         DSRBasicCodedEntry("RWV", "DCM", "Real World Value Map")
 #define CODE_DCM_Segmentation_SEG                                          DSRBasicCodedEntry("SEG", "DCM", "Segmentation")
 #define CODE_DCM_SlideMicroscopy_SM                                        DSRBasicCodedEntry("SM", "DCM", "Slide Microscopy")
 #define CODE_DCM_VoltageMeasurementByBasketCatheter                        DSRBasicCodedEntry("109011", "DCM", "Voltage measurement by basket catheter")
 #define CODE_DCM_VoltageMeasurementByMappingCatheter                       DSRBasicCodedEntry("109012", "DCM", "Voltage measurement by mapping catheter")
 #define CODE_DCM_VoltageMeasurement                                        DSRBasicCodedEntry("109013", "DCM", "Voltage measurement")
-#define CODE_DCM_35PercentOfThermalCO                                      DSRBasicCodedEntry("109014", "DCM", "35% of thermal CO")
-#define CODE_DCM_70PercentOfThermalCO                                      DSRBasicCodedEntry("109015", "DCM", "70% of thermal CO")
+#define CODE_DCM_35PercentOfThermalDyeDilutionCO                           DSRBasicCodedEntry("109014", "DCM", "35% of thermal/dye dilution CO")
+#define CODE_DCM_70PercentOfThermalDyeDilutionCO                           DSRBasicCodedEntry("109015", "DCM", "70% of thermal/dye dilution CO")
 #define CODE_DCM_AWavePeakPressure                                         DSRBasicCodedEntry("109016", "DCM", "A wave peak pressure")
 #define CODE_DCM_AWavePressure_average                                     DSRBasicCodedEntry("109017", "DCM", "A wave pressure, average")
 #define CODE_DCM_BeatDetected_accepted                                     DSRBasicCodedEntry("109018", "DCM", "Beat detected (accepted)")
 #define CODE_DCM_PeakOfThermalCardiacOutputBolus                           DSRBasicCodedEntry("109028", "DCM", "Peak of thermal cardiac output bolus")
 #define CODE_DCM_StartOfExpiration                                         DSRBasicCodedEntry("109029", "DCM", "Start of expiration")
 #define CODE_DCM_StartOfInspiration                                        DSRBasicCodedEntry("109030", "DCM", "Start of inspiration")
-#define CODE_DCM_StartOfThermalCardiacOutputBolus                          DSRBasicCodedEntry("109031", "DCM", "Start of thermal cardiac output bolus")
+#define CODE_DCM_StartOfThermalCO                                          DSRBasicCodedEntry("109031", "DCM", "Start of thermal CO")
 #define CODE_DCM_RETIRED_SystolicPressure_average                          DSRBasicCodedEntry("109032", "DCM", "Systolic pressure, average")
 #define CODE_DCM_RETIRED_SystolicPeakPressure                              DSRBasicCodedEntry("109033", "DCM", "Systolic peak pressure")
 #define CODE_DCM_VWavePeakPressure                                         DSRBasicCodedEntry("109034", "DCM", "V wave peak pressure")
 #define CODE_DCM_IndividualImpressionRecommendation                        DSRBasicCodedEntry("111034", "DCM", "Individual Impression/Recommendation")
 #define CODE_DCM_LesionDensity                                             DSRBasicCodedEntry("111035", "DCM", "Lesion Density")
 #define CODE_DCM_MammographyCADReport                                      DSRBasicCodedEntry("111036", "DCM", "Mammography CAD Report")
-#define CODE_DCM_Margins                                                   DSRBasicCodedEntry("111037", "DCM", "Margins")
+#define CODE_DCM_RETIRED_Margins                                           DSRBasicCodedEntry("111037", "DCM", "Margins")
 #define CODE_DCM_NumberOfCalcifications                                    DSRBasicCodedEntry("111038", "DCM", "Number of calcifications")
 #define CODE_DCM_ObjectType                                                DSRBasicCodedEntry("111039", "DCM", "Object type")
 #define CODE_DCM_OriginalSource                                            DSRBasicCodedEntry("111040", "DCM", "Original Source")
 #define CODE_DCM_BarrettUniversalII                                        DSRBasicCodedEntry("111865", "DCM", "Barrett Universal II")
 #define CODE_DCM_BarrettLensFactor                                         DSRBasicCodedEntry("111866", "DCM", "Barrett Lens Factor")
 #define CODE_DCM_BarrettDesignFactor                                       DSRBasicCodedEntry("111867", "DCM", "Barrett Design Factor")
+#define CODE_DCM_Kane                                                      DSRBasicCodedEntry("111868", "DCM", "Kane")
+#define CODE_DCM_KaneToric                                                 DSRBasicCodedEntry("111869", "DCM", "Kane Toric")
+#define CODE_DCM_KaneKeratoconus                                           DSRBasicCodedEntry("111870", "DCM", "Kane Keratoconus")
+#define CODE_DCM_BarrettKeratoconus                                        DSRBasicCodedEntry("111871", "DCM", "Barrett Keratoconus")
+#define CODE_DCM_BarrettRx                                                 DSRBasicCodedEntry("111872", "DCM", "Barrett Rx")
+#define CODE_DCM_EVO                                                       DSRBasicCodedEntry("111873", "DCM", "EVO")
+#define CODE_DCM_ShammasNoHistory                                          DSRBasicCodedEntry("111874", "DCM", "Shammas No-History")
+#define CODE_DCM_CamellinCalossi                                           DSRBasicCodedEntry("111875", "DCM", "Camellin-Calossi")
+#define CODE_DCM_HillRBF3dot0                                              DSRBasicCodedEntry("111876", "DCM", "Hill RBF 3.0")
+#define CODE_DCM_PEARLDGS                                                  DSRBasicCodedEntry("111877", "DCM", "PEARL-DGS")
 #define CODE_DCM_MaculaCentered                                            DSRBasicCodedEntry("111900", "DCM", "Macula centered")
 #define CODE_DCM_DiscCentered                                              DSRBasicCodedEntry("111901", "DCM", "Disc centered")
 #define CODE_DCM_LesionCentered                                            DSRBasicCodedEntry("111902", "DCM", "Lesion centered")
 #define CODE_DCM_MinimumIntensityProjection                                DSRBasicCodedEntry("113079", "DCM", "Minimum intensity projection")
 #define CODE_DCM_GlutamateAndGlutamine                                     DSRBasicCodedEntry("113080", "DCM", "Glutamate and glutamine")
 #define CODE_DCM_CholineCreatineRatio                                      DSRBasicCodedEntry("113081", "DCM", "Choline/Creatine Ratio")
-#define CODE_DCM_NAcetylaspartateCreatineRatio                             DSRBasicCodedEntry("113082", "DCM", "N-acetylaspartate /Creatine Ratio")
-#define CODE_DCM_NAcetylaspartateCholineRatio                              DSRBasicCodedEntry("113083", "DCM", "N-acetylaspartate /Choline Ratio")
+#define CODE_DCM_NAcetylaspartateCreatineRatio                             DSRBasicCodedEntry("113082", "DCM", "N-acetylaspartate/Creatine Ratio")
+#define CODE_DCM_NAcetylaspartateCholineRatio                              DSRBasicCodedEntry("113083", "DCM", "N-acetylaspartate/Choline Ratio")
 #define CODE_DCM_Tmax                                                      DSRBasicCodedEntry("113084", "DCM", "Tmax")
 #define CODE_DCM_SpatialResampling                                         DSRBasicCodedEntry("113085", "DCM", "Spatial resampling")
 #define CODE_DCM_EdgeEnhancement                                           DSRBasicCodedEntry("113086", "DCM", "Edge enhancement")
 #define CODE_DCM_PolarToRectangularScanConversion                          DSRBasicCodedEntry("113093", "DCM", "Polar to Rectangular Scan Conversion")
 #define CODE_DCM_CreatineAndCholine                                        DSRBasicCodedEntry("113094", "DCM", "Creatine and Choline")
 #define CODE_DCM_LipidAndLactate                                           DSRBasicCodedEntry("113095", "DCM", "Lipid and Lactate")
-#define CODE_DCM_CreatinePlusCholineCitrateRatio                           DSRBasicCodedEntry("113096", "DCM", "Creatine+Choline/ Citrate Ratio")
+#define CODE_DCM_CreatinePlusCholineCitrateRatio                           DSRBasicCodedEntry("113096", "DCM", "Creatine+Choline/Citrate Ratio")
 #define CODE_DCM_MultiEnergyProportionalWeighting                          DSRBasicCodedEntry("113097", "DCM", "Multi-energy proportional weighting")
 #define CODE_DCM_MagnetizationTransferRatio                                DSRBasicCodedEntry("113098", "DCM", "Magnetization Transfer Ratio")
 #define CODE_DCM_BasicApplicationConfidentialityProfile                    DSRBasicCodedEntry("113100", "DCM", "Basic Application Confidentiality Profile")
 #define CODE_DCM_RetainInstitutionIdentityOption                           DSRBasicCodedEntry("113112", "DCM", "Retain Institution Identity Option")
 #define CODE_DCM_PredecessorContainingGroupOfImagingSubjects               DSRBasicCodedEntry("113130", "DCM", "Predecessor containing group of imaging subjects")
 #define CODE_DCM_ExtractionOfIndividualSubjectFromGroup                    DSRBasicCodedEntry("113131", "DCM", "Extraction of individual subject from group")
-#define CODE_DCM_SingleSubjectSelectedFromGroup                            DSRBasicCodedEntry("113132", "DCM", "Single subject selected from group")
+#define CODE_DCM_SingleSubjectExtractedFromGroup                           DSRBasicCodedEntry("113132", "DCM", "Single subject extracted from group")
 #define CODE_DCM_Trace                                                     DSRBasicCodedEntry("113201", "DCM", "Trace")
 #define CODE_DCM_MeanDiffusivity                                           DSRBasicCodedEntry("113202", "DCM", "Mean Diffusivity")
 #define CODE_DCM_RadialDiffusivity                                         DSRBasicCodedEntry("113203", "DCM", "Radial Diffusivity")
 #define CODE_DCM_RadialKurtosis                                            DSRBasicCodedEntry("113207", "DCM", "Radial Kurtosis")
 #define CODE_DCM_AxialKurtosis                                             DSRBasicCodedEntry("113208", "DCM", "Axial Kurtosis")
 #define CODE_DCM_FractionalKurtosisAnisotropy                              DSRBasicCodedEntry("113209", "DCM", "Fractional Kurtosis Anisotropy")
-#define CODE_DCM_DeterministicTrackingAlgorithm                            DSRBasicCodedEntry("113211", "DCM", "Deterministic Tracking Algorithm")
-#define CODE_DCM_ProbabilisticTrackingAlgorithm                            DSRBasicCodedEntry("113212", "DCM", "Probabilistic Tracking Algorithm")
-#define CODE_DCM_GlobalTrackingAlgorithm                                   DSRBasicCodedEntry("113213", "DCM", "Global Tracking Algorithm")
+#define CODE_DCM_Deterministic                                             DSRBasicCodedEntry("113211", "DCM", "Deterministic")
+#define CODE_DCM_Probabilistic                                             DSRBasicCodedEntry("113212", "DCM", "Probabilistic")
+#define CODE_DCM_Global                                                    DSRBasicCodedEntry("113213", "DCM", "Global")
 #define CODE_DCM_FACT                                                      DSRBasicCodedEntry("113214", "DCM", "FACT")
 #define CODE_DCM_Streamline                                                DSRBasicCodedEntry("113215", "DCM", "Streamline")
 #define CODE_DCM_TEND                                                      DSRBasicCodedEntry("113216", "DCM", "TEND")
-#define CODE_DCM_BootstrapTrackingAlgorithm                                DSRBasicCodedEntry("113217", "DCM", "Bootstrap Tracking Algorithm")
+#define CODE_DCM_Bootstrap                                                 DSRBasicCodedEntry("113217", "DCM", "Bootstrap")
 #define CODE_DCM_Euler                                                     DSRBasicCodedEntry("113218", "DCM", "Euler")
 #define CODE_DCM_RungeKutta                                                DSRBasicCodedEntry("113219", "DCM", "Runge-Kutta")
 #define CODE_DCM_HARDI                                                     DSRBasicCodedEntry("113221", "DCM", "HARDI")
 #define CODE_DCM_DSI                                                       DSRBasicCodedEntry("113224", "DCM", "DSI")
 #define CODE_DCM_LSDI                                                      DSRBasicCodedEntry("113225", "DCM", "LSDI")
 #define CODE_DCM_SingleShotEPI                                             DSRBasicCodedEntry("113226", "DCM", "Single Shot EPI")
-#define CODE_DCM_MultiShotEPI                                              DSRBasicCodedEntry("113227", "DCM", "Multi Shot EPI")
+#define CODE_DCM_MultipleShotEPI                                           DSRBasicCodedEntry("113227", "DCM", "Multiple Shot EPI")
 #define CODE_DCM_ParallelImaging                                           DSRBasicCodedEntry("113228", "DCM", "Parallel Imaging")
 #define CODE_DCM_SingleTensor                                              DSRBasicCodedEntry("113231", "DCM", "Single Tensor")
 #define CODE_DCM_MultiTensor                                               DSRBasicCodedEntry("113232", "DCM", "Multi Tensor")
 #define CODE_DCM_ICRPPublication53                                         DSRBasicCodedEntry("113521", "DCM", "ICRP Publication 53")
 #define CODE_DCM_ICRPPublication80                                         DSRBasicCodedEntry("113522", "DCM", "ICRP Publication 80")
 #define CODE_DCM_ICRPPublication106                                        DSRBasicCodedEntry("113523", "DCM", "ICRP Publication 106")
+#define CODE_DCM_ICRPPublication128                                        DSRBasicCodedEntry("113524", "DCM", "ICRP Publication 128")
+#define CODE_DCM_RADAR2017                                                 DSRBasicCodedEntry("113525", "DCM", "RADAR 2017")
 #define CODE_DCM_MIRDOSE                                                   DSRBasicCodedEntry("113526", "DCM", "MIRDOSE")
 #define CODE_DCM_OLINDAEXM                                                 DSRBasicCodedEntry("113527", "DCM", "OLINDA-EXM")
 #define CODE_DCM_PackageInsert                                             DSRBasicCodedEntry("113528", "DCM", "Package Insert")
 #define CODE_DCM_ActivityMeasurementDevice                                 DSRBasicCodedEntry("113540", "DCM", "Activity Measurement Device")
 #define CODE_DCM_DoseCalibrator                                            DSRBasicCodedEntry("113541", "DCM", "Dose Calibrator")
 #define CODE_DCM_InfusionSystem                                            DSRBasicCodedEntry("113542", "DCM", "Infusion System")
-#define CODE_DCM_Generator                                                 DSRBasicCodedEntry("113543", "DCM", "Generator")
+#define CODE_DCM_RadioisotopeGenerator                                     DSRBasicCodedEntry("113543", "DCM", "Radioisotope Generator")
 #define CODE_DCM_FastingDuration                                           DSRBasicCodedEntry("113550", "DCM", "Fasting Duration")
 #define CODE_DCM_HydrationVolume                                           DSRBasicCodedEntry("113551", "DCM", "Hydration Volume")
 #define CODE_DCM_RecentPhysicalActivity                                    DSRBasicCodedEntry("113552", "DCM", "Recent Physical Activity")
 #define CODE_DCM_ACRAccreditationPhantom_PET                               DSRBasicCodedEntry("113687", "DCM", "ACR Accreditation Phantom - PET")
 #define CODE_DCM_ACRAccreditationPhantom_ECTPET                            DSRBasicCodedEntry("113688", "DCM", "ACR Accreditation Phantom - ECT/PET")
 #define CODE_DCM_ACRAccreditationPhantom_PETFaceplate                      DSRBasicCodedEntry("113689", "DCM", "ACR Accreditation Phantom - PET Faceplate")
-#define CODE_DCM_IECHeadDosimetryPhantom                                   DSRBasicCodedEntry("113690", "DCM", "IEC Head Dosimetry Phantom")
-#define CODE_DCM_IECBodyDosimetryPhantom                                   DSRBasicCodedEntry("113691", "DCM", "IEC Body Dosimetry Phantom")
+#define CODE_DCM_IEC160mmHeadCTDosimetryPhantom                            DSRBasicCodedEntry("113690", "DCM", "IEC 160mm Head CT Dosimetry Phantom")
+#define CODE_DCM_IEC320mmBodyCTDosimetryPhantom                            DSRBasicCodedEntry("113691", "DCM", "IEC 320mm Body CT Dosimetry Phantom")
 #define CODE_DCM_NEMAXR212000Phantom                                       DSRBasicCodedEntry("113692", "DCM", "NEMA XR21-2000 Phantom")
 #define CODE_DCM_XRayRadiationDoseReport                                   DSRBasicCodedEntry("113701", "DCM", "X-Ray Radiation Dose Report")
 #define CODE_DCM_AccumulatedXRayDoseData                                   DSRBasicCodedEntry("113702", "DCM", "Accumulated X-Ray Dose Data")
 #define CODE_DCM_PerformedProcedureStepSOPInstanceUID                      DSRBasicCodedEntry("121126", "DCM", "Performed Procedure Step SOP Instance UID")
 #define CODE_DCM_PerformedProcedureStepSOPClassUID                         DSRBasicCodedEntry("121127", "DCM", "Performed Procedure Step SOP Class UID")
 #define CODE_DCM_ProcedureActionDuration                                   DSRBasicCodedEntry("121128", "DCM", "Procedure Action Duration")
-#define CODE_DCM_StartProcedureActionItem                                  DSRBasicCodedEntry("121130", "DCM", "Start Procedure Action Item")
-#define CODE_DCM_EndProcedureActionItem                                    DSRBasicCodedEntry("121131", "DCM", "End Procedure Action Item")
-#define CODE_DCM_SuspendProcedureActionItem                                DSRBasicCodedEntry("121132", "DCM", "Suspend Procedure Action Item")
-#define CODE_DCM_ResumeProcedureActionItem                                 DSRBasicCodedEntry("121133", "DCM", "Resume Procedure Action Item")
+#define CODE_DCM_StartProcedureAction                                      DSRBasicCodedEntry("121130", "DCM", "Start Procedure Action")
+#define CODE_DCM_EndProcedureAction                                        DSRBasicCodedEntry("121131", "DCM", "End Procedure Action")
+#define CODE_DCM_SuspendProcedureAction                                    DSRBasicCodedEntry("121132", "DCM", "Suspend Procedure Action")
+#define CODE_DCM_ResumeProcedureAction                                     DSRBasicCodedEntry("121133", "DCM", "Resume Procedure Action")
 #define CODE_DCM_ObservationDateTimeQualifier                              DSRBasicCodedEntry("121135", "DCM", "Observation DateTime Qualifier")
 #define CODE_DCM_DateTimeUnsynchronized                                    DSRBasicCodedEntry("121136", "DCM", "DateTime Unsynchronized")
 #define CODE_DCM_DateTimeEstimated                                         DSRBasicCodedEntry("121137", "DCM", "DateTime Estimated")
 #define CODE_DCM_OxygenAdministrationRate                                  DSRBasicCodedEntry("121160", "DCM", "Oxygen Administration Rate")
 #define CODE_DCM_BeginOxygenAdministration                                 DSRBasicCodedEntry("121161", "DCM", "Begin Oxygen Administration")
 #define CODE_DCM_EndOxygenAdministration                                   DSRBasicCodedEntry("121162", "DCM", "End oxygen administration")
-#define CODE_DCM_ByVentilator                                              DSRBasicCodedEntry("121163", "DCM", "By ventilator")
+#define CODE_DCM_OxygenAdministrationByVentilator                          DSRBasicCodedEntry("121163", "DCM", "Oxygen Administration by ventilator")
 #define CODE_DCM_PatientAssessmentPerformed                                DSRBasicCodedEntry("121165", "DCM", "Patient Assessment Performed")
 #define CODE_DCM_BeginPacing                                               DSRBasicCodedEntry("121166", "DCM", "Begin Pacing")
 #define CODE_DCM_EndPacing                                                 DSRBasicCodedEntry("121167", "DCM", "End Pacing")
 #define CODE_DCM_AddendedReport                                            DSRBasicCodedEntry("121361", "DCM", "Addended report")
 #define CODE_DCM_PreliminaryReport                                         DSRBasicCodedEntry("121362", "DCM", "Preliminary report")
 #define CODE_DCM_PartialReport                                             DSRBasicCodedEntry("121363", "DCM", "Partial report")
+#define CODE_DCM_ComposedFromDeformableRegistration                        DSRBasicCodedEntry("121367", "DCM", "Composed from deformable registration")
+#define CODE_DCM_ComposedFromImageSeriesOtherThanPlanningImageSeries       DSRBasicCodedEntry("121368", "DCM", "Composed from image series other than planning image series")
+#define CODE_DCM_ComposedFromSetupPerturbation                             DSRBasicCodedEntry("121369", "DCM", "Composed from setup perturbation")
 #define CODE_DCM_ComposedFromPriorDoses                                    DSRBasicCodedEntry("121370", "DCM", "Composed from prior doses")
 #define CODE_DCM_ComposedFromPriorDosesAndCurrentPlan                      DSRBasicCodedEntry("121371", "DCM", "Composed from prior doses and current plan")
 #define CODE_DCM_SourceDoseForComposingCurrentDose                         DSRBasicCodedEntry("121372", "DCM", "Source dose for composing current dose")
 #define CODE_DCM_NumberOfFractionsCompleted                                DSRBasicCodedEntry("121387", "DCM", "Number of Fractions Completed")
 #define CODE_DCM_CheckedInStatus                                           DSRBasicCodedEntry("121388", "DCM", "Checked-In Status")
 #define CODE_DCM_ReferencedBeamNumber                                      DSRBasicCodedEntry("121389", "DCM", "Referenced Beam Number")
+#define CODE_DCM_ClinicalFractionNumber                                    DSRBasicCodedEntry("121390", "DCM", "Clinical Fraction Number")
 #define CODE_DCM_Derivation                                                DSRBasicCodedEntry("121401", "DCM", "Derivation")
 #define CODE_DCM_Normality                                                 DSRBasicCodedEntry("121402", "DCM", "Normality")
 #define CODE_DCM_LevelOfSignificance                                       DSRBasicCodedEntry("121403", "DCM", "Level of Significance")
 #define CODE_DCM_RTTreatmentQAByRTPlanDoseCheck                            DSRBasicCodedEntry("121731", "DCM", "RT Treatment QA by RT Plan Dose Check")
 #define CODE_DCM_RTTreatmentQAByRTPlanDifferenceCheck                      DSRBasicCodedEntry("121732", "DCM", "RT Treatment QA by RT Plan Difference Check")
 #define CODE_DCM_RTTreatmentQAByRTIonPlanDoseCheck                         DSRBasicCodedEntry("121733", "DCM", "RT Treatment QA by RT Ion Plan Dose Check")
-#define CODE_DCM_RTTreatmentQAWithRTIonPlanDifferenceCheck                 DSRBasicCodedEntry("121734", "DCM", "RT Treatment QA with RT Ion Plan Difference Check")
+#define CODE_DCM_RTTreatmentQAByRTIonPlanDifferenceCheck                   DSRBasicCodedEntry("121734", "DCM", "RT Treatment QA by RT Ion Plan Difference Check")
 #define CODE_DCM_RTBrachyTreatment                                         DSRBasicCodedEntry("121735", "DCM", "RT Brachy Treatment")
 #define CODE_DCM_RTImageGuidedPatientPositioningAndTreatmentDelivery       DSRBasicCodedEntry("121736", "DCM", "RT Image-Guided Patient Positioning and Treatment Delivery")
 #define CODE_DCM_RTPatientPositionAcquisition_MR                           DSRBasicCodedEntry("121737", "DCM", "RT Patient Position Acquisition, MR")
 #define CODE_DCM_Probability                                               DSRBasicCodedEntry("122157", "DCM", "Probability")
 #define CODE_DCM_ECGGlobalMeasurements                                     DSRBasicCodedEntry("122158", "DCM", "ECG Global Measurements")
 #define CODE_DCM_ECGLeadMeasurements                                       DSRBasicCodedEntry("122159", "DCM", "ECG Lead Measurements")
-#define CODE_DCM_DerivedArea_NonValve                                      DSRBasicCodedEntry("122160", "DCM", "Derived Area, Non-Valve")
+#define CODE_DCM_DerivedNonValveArea                                       DSRBasicCodedEntry("122160", "DCM", "Derived Non-Valve Area")
 #define CODE_DCM_PulmonaryFlow                                             DSRBasicCodedEntry("122161", "DCM", "Pulmonary Flow")
 #define CODE_DCM_SystemicFlow                                              DSRBasicCodedEntry("122162", "DCM", "Systemic Flow")
 #define CODE_DCM_DischargeDateTime                                         DSRBasicCodedEntry("122163", "DCM", "Discharge DateTime")
 #define CODE_DCM_TerritoryRegionSeverity                                   DSRBasicCodedEntry("122459", "DCM", "Territory Region Severity")
 #define CODE_DCM_OppositeRegionSeverity                                    DSRBasicCodedEntry("122461", "DCM", "Opposite Region Severity")
 #define CODE_DCM_LADRegionInRAOProjection                                  DSRBasicCodedEntry("122464", "DCM", "LAD Region in RAO Projection")
-#define CODE_DCM_RCARegionInROAProjection                                  DSRBasicCodedEntry("122465", "DCM", "RCA Region in ROA Projection")
+#define CODE_DCM_RCARegionInRAOProjection                                  DSRBasicCodedEntry("122465", "DCM", "RCA Region in RAO Projection")
 #define CODE_DCM_SingleLADRegionInRAOProjection                            DSRBasicCodedEntry("122466", "DCM", "Single LAD Region in RAO Projection")
 #define CODE_DCM_SingleRCARegionInRAOProjection                            DSRBasicCodedEntry("122467", "DCM", "Single RCA Region in RAO Projection")
 #define CODE_DCM_MultipleLADRegionInRAOProjection                          DSRBasicCodedEntry("122468", "DCM", "Multiple LAD Region in RAO Projection")
 #define CODE_DCM_STDepression_Downsloping                                  DSRBasicCodedEntry("122759", "DCM", "ST Depression - Downsloping")
 #define CODE_DCM_StressTestScore                                           DSRBasicCodedEntry("122760", "DCM", "Stress test score")
 #define CODE_DCM_NumberOfDiseasedVesselTerritories                         DSRBasicCodedEntry("122762", "DCM", "Number of diseased vessel territories")
-#define CODE_DCM_WeightExceedsEquipmentLimit                               DSRBasicCodedEntry("122764", "DCM", "Weight exceeds equipment limit")
+#define CODE_DCM_PatientWeightExceedsEquipmentLimit                        DSRBasicCodedEntry("122764", "DCM", "Patient weight exceeds equipment limit")
 #define CODE_DCM_DifferenceInEjectionFraction                              DSRBasicCodedEntry("122768", "DCM", "Difference in Ejection Fraction")
 #define CODE_DCM_DifferenceInEDLVVolume                                    DSRBasicCodedEntry("122769", "DCM", "Difference in ED LV Volume")
 #define CODE_DCM_RatioOfAchievedToPredictedMaximalOxygenConsumption        DSRBasicCodedEntry("122770", "DCM", "Ratio of achieved to predicted maximal oxygen consumption")
 #define CODE_DCM_AcquisitionProtocol                                       DSRBasicCodedEntry("125203", "DCM", "Acquisition Protocol")
 #define CODE_DCM_AreaLengthBiplane                                         DSRBasicCodedEntry("125204", "DCM", "Area-length biplane")
 #define CODE_DCM_AreaLengthSinglePlane                                     DSRBasicCodedEntry("125205", "DCM", "Area-Length Single Plane")
-#define CODE_DCM_Cube                                                      DSRBasicCodedEntry("125206", "DCM", "Cube")
+#define CODE_DCM_CubeMethod                                                DSRBasicCodedEntry("125206", "DCM", "Cube Method")
 #define CODE_DCM_MethodOfDisks_Biplane                                     DSRBasicCodedEntry("125207", "DCM", "Method of Disks, Biplane")
 #define CODE_DCM_MethodOfDisks_SinglePlane                                 DSRBasicCodedEntry("125208", "DCM", "Method of Disks, Single Plane")
 #define CODE_DCM_Teichholz                                                 DSRBasicCodedEntry("125209", "DCM", "Teichholz")
 #define CODE_DCM_Glycolysis                                                DSRBasicCodedEntry("126034", "DCM", "Glycolysis")
 #define CODE_DCM_TotalLesionProliferation                                  DSRBasicCodedEntry("126035", "DCM", "Total Lesion Proliferation")
 #define CODE_DCM_ProliferativeActivity                                     DSRBasicCodedEntry("126036", "DCM", "Proliferative Activity")
-#define CODE_DCM_StandardizedAddedMetabolicActivity_SAM                    DSRBasicCodedEntry("126037", "DCM", "Standardized Added Metabolic Activity (SAM)")
-#define CODE_DCM_StandardizedAddedMetabolicActivity_SAM_Background         DSRBasicCodedEntry("126038", "DCM", "Standardized Added Metabolic Activity (SAM) Background")
+#define CODE_DCM_StandardizedAddedMetabolicActivity                        DSRBasicCodedEntry("126037", "DCM", "Standardized Added Metabolic Activity")
+#define CODE_DCM_StandardizedAddedMetabolicActivityBackground              DSRBasicCodedEntry("126038", "DCM", "Standardized Added Metabolic Activity Background")
 #define CODE_DCM_LesionToBackgroundSUVRatio                                DSRBasicCodedEntry("126039", "DCM", "Lesion to Background SUV Ratio")
 #define CODE_DCM_BackgroundForLesionToBackgroundSUVRatio                   DSRBasicCodedEntry("126040", "DCM", "Background for Lesion to Background SUV Ratio")
 #define CODE_DCM_FractalDimension                                          DSRBasicCodedEntry("126050", "DCM", "Fractal Dimension")
 #define CODE_DCM_PerfusionAnalysisByIVIodinatedContrastCTTechnique         DSRBasicCodedEntry("126301", "DCM", "Perfusion analysis by IV Iodinated Contrast CT technique")
 #define CODE_DCM_PerfusionAnalysisByArterialSpinLabelingMRTechnique        DSRBasicCodedEntry("126302", "DCM", "Perfusion analysis by Arterial Spin Labeling MR technique")
 #define CODE_DCM_PerfusionAnalysisBySusceptibilityMRTechnique              DSRBasicCodedEntry("126303", "DCM", "Perfusion analysis by Susceptibility MR technique")
-#define CODE_DCM_LeastMeanSquare_LMS_deconvolution                         DSRBasicCodedEntry("126310", "DCM", "Least Mean Square (LMS) deconvolution")
-#define CODE_DCM_SingularValueDecomposition_SVD_deconvolution              DSRBasicCodedEntry("126311", "DCM", "Singular Value Decomposition (SVD) deconvolution")
+#define CODE_DCM_LeastMeanSquareDeconvolution                              DSRBasicCodedEntry("126310", "DCM", "Least Mean Square deconvolution")
+#define CODE_DCM_SingularValueDecompositionDeconvolution                   DSRBasicCodedEntry("126311", "DCM", "Singular Value Decomposition deconvolution")
 #define CODE_DCM_Ktrans                                                    DSRBasicCodedEntry("126312", "DCM", "Ktrans")
 #define CODE_DCM_Kep                                                       DSRBasicCodedEntry("126313", "DCM", "kep")
 #define CODE_DCM_Ve                                                        DSRBasicCodedEntry("126314", "DCM", "ve")
 #define CODE_DCM_IAUC90                                                    DSRBasicCodedEntry("126322", "DCM", "IAUC90")
 #define CODE_DCM_IAUC180                                                   DSRBasicCodedEntry("126323", "DCM", "IAUC180")
 #define CODE_DCM_IAUCBN                                                    DSRBasicCodedEntry("126324", "DCM", "IAUCBN")
-#define CODE_DCM_IAUCBN60                                                  DSRBasicCodedEntry("126325", "DCM", "IAUCBN60")
-#define CODE_DCM_IAUCBN90                                                  DSRBasicCodedEntry("126326", "DCM", "IAUCBN90")
-#define CODE_DCM_AUCBN180                                                  DSRBasicCodedEntry("126327", "DCM", "AUCBN180")
+#define CODE_DCM_IAUC60BN                                                  DSRBasicCodedEntry("126325", "DCM", "IAUC60BN")
+#define CODE_DCM_IAUC90BN                                                  DSRBasicCodedEntry("126326", "DCM", "IAUC90BN")
+#define CODE_DCM_IAUC180BN                                                 DSRBasicCodedEntry("126327", "DCM", "IAUC180BN")
 #define CODE_DCM_Tau_m                                                     DSRBasicCodedEntry("126330", "DCM", "tau_m")
 #define CODE_DCM_Vp                                                        DSRBasicCodedEntry("126331", "DCM", "vp")
 #define CODE_DCM_StandardToftsModel                                        DSRBasicCodedEntry("126340", "DCM", "Standard Tofts Model")
 #define CODE_DCM_ExtendedToftsModel                                        DSRBasicCodedEntry("126341", "DCM", "Extended Tofts Model")
 #define CODE_DCM_ModelFreeConcentrationTimeQuantitification                DSRBasicCodedEntry("126342", "DCM", "Model-free concentration-time quantitification")
-#define CODE_DCM_FirstPassLeakageProfile_FPLP_Model                        DSRBasicCodedEntry("126343", "DCM", "First Pass Leakage Profile (FPLP) Model")
-#define CODE_DCM_ShutterSpeedModel_SSM                                     DSRBasicCodedEntry("126344", "DCM", "Shutter-Speed Model (SSM)")
-#define CODE_DCM_GammaCapillaryTransitTime_GCCT_Model                      DSRBasicCodedEntry("126345", "DCM", "Gamma Capillary Transit Time (GCCT) Model")
-#define CODE_DCM_AdiabaticTissueHomogeneity_ATH_Model                      DSRBasicCodedEntry("126346", "DCM", "Adiabatic Tissue Homogeneity (ATH) Model")
-#define CODE_DCM_TwoCompartmentExchange_2CX_Model                          DSRBasicCodedEntry("126347", "DCM", "Two Compartment Exchange (2CX) Model")
+#define CODE_DCM_FirstPassLeakageProfileModel                              DSRBasicCodedEntry("126343", "DCM", "First Pass Leakage Profile Model")
+#define CODE_DCM_ShutterSpeedModel                                         DSRBasicCodedEntry("126344", "DCM", "Shutter-Speed Model")
+#define CODE_DCM_GammaCapillaryTransitTimeModel                            DSRBasicCodedEntry("126345", "DCM", "Gamma Capillary Transit Time Model")
+#define CODE_DCM_AdiabaticTissueHomogeneityModel                           DSRBasicCodedEntry("126346", "DCM", "Adiabatic Tissue Homogeneity Model")
+#define CODE_DCM_TwoCompartmentExchangeModel                               DSRBasicCodedEntry("126347", "DCM", "Two Compartment Exchange Model")
 #define CODE_DCM_T1ByMultipleFlipAngles                                    DSRBasicCodedEntry("126350", "DCM", "T1 by Multiple Flip Angles")
 #define CODE_DCM_T1ByInversionRecovery                                     DSRBasicCodedEntry("126351", "DCM", "T1 by Inversion Recovery")
 #define CODE_DCM_T1ByFixedValue                                            DSRBasicCodedEntry("126352", "DCM", "T1 by Fixed Value")
 #define CODE_DCM_T807_F18                                                  DSRBasicCodedEntry("126502", "DCM", "T807 F^18^")
 #define CODE_DCM_Flubatine_F18                                             DSRBasicCodedEntry("126503", "DCM", "Flubatine F^18^")
 #define CODE_DCM_Lutetium177NAcetylaspartylglutamate                       DSRBasicCodedEntry("126509", "DCM", "Lutetium^177^ n-acetylaspartylglutamate")
-#define CODE_DCM_MonoclonalAntibody_mAb_64Cu                               DSRBasicCodedEntry("126510", "DCM", "Monoclonal Antibody (mAb) ^64^Cu")
-#define CODE_DCM_MonoclonalAntibody_mAb_89Zr                               DSRBasicCodedEntry("126511", "DCM", "Monoclonal Antibody (mAb) ^89^Zr")
+#define CODE_DCM_MonoclonalAntibody_64Cu                                   DSRBasicCodedEntry("126510", "DCM", "Monoclonal Antibody ^64^Cu")
+#define CODE_DCM_MonoclonalAntibody_89Zr                                   DSRBasicCodedEntry("126511", "DCM", "Monoclonal Antibody ^89^Zr")
 #define CODE_DCM_Trastuzumab_89Zr                                          DSRBasicCodedEntry("126512", "DCM", "Trastuzumab ^89^Zr")
 #define CODE_DCM_Cetuximab_89Zr                                            DSRBasicCodedEntry("126513", "DCM", "Cetuximab ^89^Zr")
 #define CODE_DCM_J591_89Zr                                                 DSRBasicCodedEntry("126514", "DCM", "J591 ^89^Zr")
 #define CODE_DCM_R1507_89Zr                                                DSRBasicCodedEntry("126518", "DCM", "R1507 ^89^Zr")
 #define CODE_DCM_E4G10_89Zr                                                DSRBasicCodedEntry("126519", "DCM", "E4G10 ^89^Zr")
 #define CODE_DCM_DfCD45_89Zr                                               DSRBasicCodedEntry("126520", "DCM", "Df-CD45 ^89^Zr")
+#define CODE_DCM_Glucose_C11                                               DSRBasicCodedEntry("126521", "DCM", "Glucose C^11^")
 #define CODE_DCM_44Scandium                                                DSRBasicCodedEntry("126600", "DCM", "^44^Scandium")
 #define CODE_DCM_51Manganese                                               DSRBasicCodedEntry("126601", "DCM", "^51^Manganese")
 #define CODE_DCM_70Arsenic                                                 DSRBasicCodedEntry("126602", "DCM", "^70^Arsenic")
 #define CODE_DCM_HeadAndNeckImagingSpecialty                               DSRBasicCodedEntry("128008", "DCM", "Head and Neck Imaging Specialty")
 #define CODE_DCM_MusculoskeletalImagingSpecialty                           DSRBasicCodedEntry("128009", "DCM", "Musculoskeletal Imaging Specialty")
 #define CODE_DCM_NeurologySpecialty                                        DSRBasicCodedEntry("128010", "DCM", "Neurology Specialty")
-#define CODE_DCM_NeuroradiologicImagingSpecialty                           DSRBasicCodedEntry("128011", "DCM", "Neuroradiologic Imaging Specialty")
+#define CODE_DCM_NeuroradiologyImagingSpecialty                            DSRBasicCodedEntry("128011", "DCM", "Neuroradiology Imaging Specialty")
 #define CODE_DCM_OBGynImagingSpecialty                                     DSRBasicCodedEntry("128012", "DCM", "OB/Gyn Imaging Specialty")
 #define CODE_DCM_OncologicImagingSpecialty                                 DSRBasicCodedEntry("128013", "DCM", "Oncologic Imaging Specialty")
 #define CODE_DCM_OncologySpecialty                                         DSRBasicCodedEntry("128014", "DCM", "Oncology Specialty")
 #define CODE_DCM_SkinDoseMap                                               DSRBasicCodedEntry("128485", "DCM", "Skin Dose Map")
 #define CODE_DCM_3DDoseMap                                                 DSRBasicCodedEntry("128487", "DCM", "3D Dose Map")
 #define CODE_DCM_DoseGradient                                              DSRBasicCodedEntry("128488", "DCM", "Dose Gradient")
-#define CODE_DCM_PhysicalSupport                                           DSRBasicCodedEntry("128492", "DCM", "Physical Support")
+#define CODE_DCM_PatientSupport                                            DSRBasicCodedEntry("128492", "DCM", "Patient Support")
 #define CODE_DCM_PatientSegmentedModel                                     DSRBasicCodedEntry("128494", "DCM", "Patient Segmented Model")
 #define CODE_DCM_DosePointCloud                                            DSRBasicCodedEntry("128496", "DCM", "Dose Point Cloud")
 #define CODE_DCM_MeasuredRadiationDose                                     DSRBasicCodedEntry("128497", "DCM", "Measured Radiation Dose")
 #define CODE_DCM_FixationOrPositioningDevice                               DSRBasicCodedEntry("130044", "DCM", "Fixation or Positioning Device")
 #define CODE_DCM_BrachytherapyDevice                                       DSRBasicCodedEntry("130045", "DCM", "Brachytherapy Device")
 #define CODE_DCM_NonSpecificVolume                                         DSRBasicCodedEntry("130046", "DCM", "Non-specific Volume")
-#define CODE_DCM_ExternalBodyStructure                                     DSRBasicCodedEntry("130047", "DCM", "External Body Structure")
+#define CODE_DCM_ExternalBodyModel                                         DSRBasicCodedEntry("130047", "DCM", "External Body Model")
 #define CODE_DCM_UnclassifiedVolume                                        DSRBasicCodedEntry("130048", "DCM", "Unclassified Volume")
 #define CODE_DCM_CTVNodal                                                  DSRBasicCodedEntry("130049", "DCM", "CTV Nodal")
 #define CODE_DCM_CTVPrimary                                                DSRBasicCodedEntry("130050", "DCM", "CTV Primary")
 #define CODE_DCM_SkinOfUpperEyelidMargin                                   DSRBasicCodedEntry("130322", "DCM", "Skin of upper eyelid margin")
 #define CODE_DCM_SkinOfMidBack                                             DSRBasicCodedEntry("130323", "DCM", "Skin of mid back")
 #define CODE_DCM_FunctionalConditionPresentDuringAcquisition               DSRBasicCodedEntry("130324", "DCM", "Functional condition present during acquisition")
+#define CODE_DCM_OrthognathicFunctionalCondition                           DSRBasicCodedEntry("130325", "DCM", "Orthognathic Functional Condition")
 #define CODE_DCM_JawPair                                                   DSRBasicCodedEntry("130330", "DCM", "Jaw Pair")
 #define CODE_DCM_LeafPairs                                                 DSRBasicCodedEntry("130331", "DCM", "Leaf Pairs")
 #define CODE_DCM_VariableCircularCollimator                                DSRBasicCodedEntry("130332", "DCM", "Variable Circular Collimator")
 #define CODE_DCM_PatientDecisionToTerminateTreatment                       DSRBasicCodedEntry("130451", "DCM", "Patient decision to terminate treatment")
 #define CODE_DCM_PhysicianDecisionToTerminateTreatment                     DSRBasicCodedEntry("130452", "DCM", "Physician decision to terminate treatment")
 #define CODE_DCM_TreatmentTerminated                                       DSRBasicCodedEntry("130453", "DCM", "Treatment Terminated")
-#define CODE_DCM_ResolvedByOverridingInterlock                             DSRBasicCodedEntry("130454", "DCM", "Resolved by overriding Interlock")
-#define CODE_DCM_ResolvedByRepositioningPatient                            DSRBasicCodedEntry("130455", "DCM", "Resolved by repositioning Patient")
+#define CODE_DCM_InterlockOverridden                                       DSRBasicCodedEntry("130454", "DCM", "Interlock Overridden")
+#define CODE_DCM_PatientRepositioned                                       DSRBasicCodedEntry("130455", "DCM", "Patient Repositioned")
 #define CODE_DCM_BolusPresent                                              DSRBasicCodedEntry("130456", "DCM", "Bolus Present")
 #define CODE_DCM_ConePresent                                               DSRBasicCodedEntry("130457", "DCM", "Cone Present")
 #define CODE_DCM_BlockPresent                                              DSRBasicCodedEntry("130458", "DCM", "Block Present")
 #define CODE_DCM_PatientSupportOrigin                                      DSRBasicCodedEntry("130538", "DCM", "Patient Support Origin")
 #define CODE_DCM_IsocenterOrigin                                           DSRBasicCodedEntry("130539", "DCM", "Isocenter Origin")
 #define CODE_DCM_PatientCoordinateSystemOrigin                             DSRBasicCodedEntry("130540", "DCM", "Patient Coordinate System Origin")
-#define CODE_DCM_10cmDosimetryPhantom                                      DSRBasicCodedEntry("130541", "DCM", "10 cm Dosimetry Phantom")
+#define CODE_DCM_100mmPediatricHeadCTDosimetryPhantom                      DSRBasicCodedEntry("130541", "DCM", "100 mm Pediatric Head CT Dosimetry Phantom")
 #define CODE_DCM_MagneticFieldStrength                                     DSRBasicCodedEntry("130542", "DCM", "Magnetic field strength")
 #define CODE_DCM_EndorectalCoilUsed                                        DSRBasicCodedEntry("130543", "DCM", "Endorectal coil used")
 #define CODE_DCM_EndorectalCoilType                                        DSRBasicCodedEntry("130544", "DCM", "Endorectal coil type")
 #define CODE_DCM_O9                                                        DSRBasicCodedEntry("130716", "DCM", "O9")
 #define CODE_DCM_O10                                                       DSRBasicCodedEntry("130717", "DCM", "O10")
 #define CODE_DCM_CoronaryArteryDiseaseAssessment                           DSRBasicCodedEntry("130720", "DCM", "Coronary Artery Disease Assessment")
-#define CODE_DCM_OronaryArteryDiseaseAssessmentModifier                    DSRBasicCodedEntry("130721", "DCM", "oronary Artery Disease Assessment Modifier")
+#define CODE_DCM_CoronaryArteryDiseaseAssessmentModifier                   DSRBasicCodedEntry("130721", "DCM", "Coronary Artery Disease Assessment Modifier")
 #define CODE_DCM_CoronaryArteryDiseaseStenosisAssessmentModifier           DSRBasicCodedEntry("130722", "DCM", "Coronary Artery Disease Stenosis Assessment Modifier")
 #define CODE_DCM_0_DocumentedAbsenceOfCAD                                  DSRBasicCodedEntry("130723", "DCM", "0 - Documented absence of CAD")
 #define CODE_DCM_1_MinimalNonObstructiveCAD                                DSRBasicCodedEntry("130724", "DCM", "1 - Minimal non-obstructive CAD")
 #define CODE_DCM_TricuspidValveAnnulusDiameter                             DSRBasicCodedEntry("131061", "DCM", "Tricuspid valve annulus diameter")
 #define CODE_DCM_IVCSWavePeakVelocity                                      DSRBasicCodedEntry("131062", "DCM", "IVC S-wave peak velocity")
 #define CODE_DCM_IVCAWavePeakVelocity                                      DSRBasicCodedEntry("131063", "DCM", "IVC a-wave peak velocity")
+#define CODE_DCM_PreProceduralStructuralHeartMeasurementReport             DSRBasicCodedEntry("131090", "DCM", "Pre-procedural Structural Heart Measurement Report")
+#define CODE_DCM_IntraProceduralStructuralHeartMeasurementReport           DSRBasicCodedEntry("131091", "DCM", "Intra-procedural Structural Heart Measurement Report")
+#define CODE_DCM_PostProceduralStructuralHeartMeasurementReport            DSRBasicCodedEntry("131092", "DCM", "Post-procedural Structural Heart Measurement Report")
+#define CODE_DCM_MidEsophageal0DegreeTEE                                   DSRBasicCodedEntry("131100", "DCM", "Mid-esophageal 0 degree TEE")
+#define CODE_DCM_MidEsophageal45DegreeTEE                                  DSRBasicCodedEntry("131101", "DCM", "Mid-esophageal 45 degree TEE")
+#define CODE_DCM_MidEsophageal60DegreeTEE                                  DSRBasicCodedEntry("131102", "DCM", "Mid-esophageal 60 degree TEE")
+#define CODE_DCM_MidEsophageal90DegreeTEE                                  DSRBasicCodedEntry("131103", "DCM", "Mid-esophageal 90 degree TEE")
+#define CODE_DCM_MidEsophageal135DegreeTEE                                 DSRBasicCodedEntry("131104", "DCM", "Mid-esophageal 135 degree TEE")
+#define CODE_DCM_BallAndDiskTypeLeftAtrialAppendageClosureDevice           DSRBasicCodedEntry("131110", "DCM", "Ball and disk type left atrial appendage closure device")
+#define CODE_DCM_BallTypeLeftAtrialAppendageClosureDevice                  DSRBasicCodedEntry("131111", "DCM", "Ball type left atrial appendage closure device")
+#define CODE_DCM_LeftAtrialAppendageClosureDevice                          DSRBasicCodedEntry("131112", "DCM", "Left atrial appendage closure device")
+#define CODE_DCM_OstiumOfLeftAuricularAppendage                            DSRBasicCodedEntry("131120", "DCM", "Ostium of Left Auricular Appendage")
+#define CODE_DCM_TransseptalPunctureHeight                                 DSRBasicCodedEntry("131130", "DCM", "Transseptal puncture height")
+#define CODE_DCM_AortaSinotubularJunctionArea                              DSRBasicCodedEntry("131140", "DCM", "Aorta sinotubular junction area")
+#define CODE_DCM_AorticAnnulusCalcificationSeverity                        DSRBasicCodedEntry("131142", "DCM", "Aortic annulus calcification severity")
+#define CODE_DCM_AorticAnnulusMaxDiameter                                  DSRBasicCodedEntry("131143", "DCM", "Aortic annulus max diameter")
+#define CODE_DCM_AorticAnnulusMinDiameter                                  DSRBasicCodedEntry("131144", "DCM", "Aortic annulus min diameter")
+#define CODE_DCM_AorticAnnulusPerimeter                                    DSRBasicCodedEntry("131145", "DCM", "Aortic annulus perimeter")
+#define CODE_DCM_AorticCalcificationVolume                                 DSRBasicCodedEntry("131146", "DCM", "Aortic calcification volume")
+#define CODE_DCM_AorticCommissuresCalcificationSeverity                    DSRBasicCodedEntry("131147", "DCM", "Aortic commissures calcification severity")
+#define CODE_DCM_AorticRootHeight                                          DSRBasicCodedEntry("131148", "DCM", "Aortic root height")
+#define CODE_DCM_AorticSinotubularJunctionDiameter                         DSRBasicCodedEntry("131149", "DCM", "Aortic sinotubular junction diameter")
+#define CODE_DCM_AorticSinusOfValsalvaArea                                 DSRBasicCodedEntry("131150", "DCM", "Aortic sinus of valsalva area")
+#define CODE_DCM_AorticValveCoaptationLength                               DSRBasicCodedEntry("131152", "DCM", "Aortic valve coaptation length")
+#define CODE_DCM_AorticValveNoncoronaryLeafletIntercommissuralAngle        DSRBasicCodedEntry("131153", "DCM", "Aortic valve noncoronary leaflet intercommissural angle")
+#define CODE_DCM_AorticValveRightLeafletIntercommissuralAngle              DSRBasicCodedEntry("131154", "DCM", "Aortic valve right leaflet intercommissural angle")
+#define CODE_DCM_AorticValveLeftLeafletIntercommissuralAngle               DSRBasicCodedEntry("131155", "DCM", "Aortic valve left leaflet intercommissural angle")
+#define CODE_DCM_AorticValveNoncoronaryLeafletIntercommissuralDistance     DSRBasicCodedEntry("131156", "DCM", "Aortic valve noncoronary leaflet intercommissural distance")
+#define CODE_DCM_AorticValveRightLeafletIntercommissuralDistance           DSRBasicCodedEntry("131157", "DCM", "Aortic valve right leaflet intercommissural distance")
+#define CODE_DCM_AorticValveLeftLeafletIntercommissuralDistance            DSRBasicCodedEntry("131158", "DCM", "Aortic valve left leaflet intercommissural distance")
+#define CODE_DCM_AorticValveLeftCoronaryLeafletHeight                      DSRBasicCodedEntry("131159", "DCM", "Aortic valve left coronary leaflet height")
+#define CODE_DCM_AorticValveLeftCoronaryLeafletLength                      DSRBasicCodedEntry("131160", "DCM", "Aortic valve left coronary leaflet length")
+#define CODE_DCM_AorticValveNoncoronaryLeafletHeight                       DSRBasicCodedEntry("131161", "DCM", "Aortic valve noncoronary leaflet height")
+#define CODE_DCM_AorticValveNoncoronaryLeafletLength                       DSRBasicCodedEntry("131162", "DCM", "Aortic valve noncoronary leaflet length")
+#define CODE_DCM_AorticValveRightCoronaryLeafletHeight                     DSRBasicCodedEntry("131163", "DCM", "Aortic valve right coronary leaflet height")
+#define CODE_DCM_AorticValveRightCoronaryLeafletLength                     DSRBasicCodedEntry("131164", "DCM", "Aortic valve right coronary leaflet length")
+#define CODE_DCM_AscendingAortaDiameter                                    DSRBasicCodedEntry("131165", "DCM", "Ascending Aorta diameter")
+#define CODE_DCM_LeftMainCoronaryOstiumHeight                              DSRBasicCodedEntry("131166", "DCM", "Left main coronary ostium height")
+#define CODE_DCM_LeftVentricularOutflowTractCalcificationSeverity          DSRBasicCodedEntry("131167", "DCM", "Left ventricular outflow tract calcification severity")
+#define CODE_DCM_MaximumAorticPlaqueThickness                              DSRBasicCodedEntry("131168", "DCM", "Maximum aortic plaque thickness")
+#define CODE_DCM_RightCoronaryArteryOstiumHeight                           DSRBasicCodedEntry("131169", "DCM", "Right coronary artery ostium height")
+#define CODE_DCM_RightVentricleDiastolicMajorAxis                          DSRBasicCodedEntry("131170", "DCM", "Right ventricle diastolic major axis")
+#define CODE_DCM_RightVentricularDiastolicMidSegmentMinorAxis              DSRBasicCodedEntry("131171", "DCM", "Right ventricular diastolic mid segment minor axis")
+#define CODE_DCM_RightVentricularDiastolicBasalMinorAxis                   DSRBasicCodedEntry("131172", "DCM", "Right ventricular diastolic basal minor axis")
+#define CODE_DCM_MitralAnteriorLeafletA1ScallopLength                      DSRBasicCodedEntry("131173", "DCM", "Mitral anterior leaflet A1 scallop length")
+#define CODE_DCM_MitralAnteriorLeafletA2ScallopLength                      DSRBasicCodedEntry("131174", "DCM", "Mitral anterior leaflet A2 scallop length")
+#define CODE_DCM_MitralAnteriorLeafletA3ScallopLength                      DSRBasicCodedEntry("131175", "DCM", "Mitral anterior leaflet A3 scallop length")
+#define CODE_DCM_MitralAnteriorLeafletArea                                 DSRBasicCodedEntry("131176", "DCM", "Mitral anterior leaflet area")
+#define CODE_DCM_AortoMitralInterAnnularAngle                              DSRBasicCodedEntry("131177", "DCM", "Aorto-mitral inter annular angle")
+#define CODE_DCM_MitralCommissureDistance                                  DSRBasicCodedEntry("131178", "DCM", "Mitral commissure distance")
+#define CODE_DCM_MitralTrigoneToTrigoneDistance                            DSRBasicCodedEntry("131179", "DCM", "Mitral trigone-to-trigone distance")
+#define CODE_DCM_MitralAnnularExcursion                                    DSRBasicCodedEntry("131180", "DCM", "Mitral annular excursion")
+#define CODE_DCM_MitralAnnulusAnterolateralToPosteromedialDiameter         DSRBasicCodedEntry("131181", "DCM", "Mitral annulus anterolateral to posteromedial diameter")
+#define CODE_DCM_MitralAnnulusAnteroposteriorDiameter                      DSRBasicCodedEntry("131182", "DCM", "Mitral annulus anteroposterior diameter")
+#define CODE_DCM_MitralAnnulusArea                                         DSRBasicCodedEntry("131183", "DCM", "Mitral annulus area")
+#define CODE_DCM_MitralAnnulusCalcificationSeverity                        DSRBasicCodedEntry("131184", "DCM", "Mitral annulus calcification severity")
+#define CODE_DCM_MitralAnnulusCommissuralDiameter                          DSRBasicCodedEntry("131185", "DCM", "Mitral annulus commissural diameter")
+#define CODE_DCM_MitralAnnulusDiameterRatio                                DSRBasicCodedEntry("131186", "DCM", "Mitral annulus diameter ratio")
+#define CODE_DCM_MitralAnnulusHeight                                       DSRBasicCodedEntry("131187", "DCM", "Mitral annulus height")
+#define CODE_DCM_MitralAnnulusNonplanarityAngle                            DSRBasicCodedEntry("131188", "DCM", "Mitral annulus nonplanarity angle")
+#define CODE_DCM_MitralAnnulusPerimeter                                    DSRBasicCodedEntry("131189", "DCM", "Mitral annulus perimeter")
+#define CODE_DCM_MitralValveCoaptationLength                               DSRBasicCodedEntry("131190", "DCM", "Mitral valve coaptation length")
+#define CODE_DCM_MitralValveInterpapillaryDistance                         DSRBasicCodedEntry("131191", "DCM", "Mitral valve interpapillary distance")
+#define CODE_DCM_AnterolateralPapillaryMuscleToTheLeftTrigone              DSRBasicCodedEntry("131192", "DCM", "Anterolateral papillary muscle to the left trigone")
+#define CODE_DCM_PosteromedialPapillaryMuscleToTheRightTrigone             DSRBasicCodedEntry("131193", "DCM", "Posteromedial papillary muscle to the right trigone")
+#define CODE_DCM_MitralValveProlapseArea                                   DSRBasicCodedEntry("131194", "DCM", "Mitral valve prolapse area")
+#define CODE_DCM_MitralValveProlapseVolume                                 DSRBasicCodedEntry("131195", "DCM", "Mitral valve prolapse volume")
+#define CODE_DCM_MitralValveSegmentFlailGap                                DSRBasicCodedEntry("131196", "DCM", "Mitral valve segment flail gap")
+#define CODE_DCM_MitralValveSphericityIndex                                DSRBasicCodedEntry("131197", "DCM", "Mitral valve sphericity index")
+#define CODE_DCM_MitralValveTentingHeight                                  DSRBasicCodedEntry("131198", "DCM", "Mitral valve tenting height")
+#define CODE_DCM_MitralValveTentingArea                                    DSRBasicCodedEntry("131199", "DCM", "Mitral valve tenting area")
+#define CODE_DCM_MitralValveTentingSegmentHeightA1P1                       DSRBasicCodedEntry("131200", "DCM", "Mitral valve tenting segment height A1-P1")
+#define CODE_DCM_MitralValveTentingSegmentHeightA2P2                       DSRBasicCodedEntry("131201", "DCM", "Mitral valve tenting segment height A2-P2")
+#define CODE_DCM_MitralValveTentingSegmentHeightA3P3                       DSRBasicCodedEntry("131202", "DCM", "Mitral valve tenting segment height A3-P3")
+#define CODE_DCM_PosteriorMitralValveLeafletArea                           DSRBasicCodedEntry("131203", "DCM", "Posterior mitral valve leaflet area")
+#define CODE_DCM_PosteriorMitralValveLeafletLength                         DSRBasicCodedEntry("131204", "DCM", "Posterior mitral valve leaflet length")
+#define CODE_DCM_PosteriorMitralValveP1LeafletScallopLength                DSRBasicCodedEntry("131205", "DCM", "Posterior mitral valve P1 leaflet scallop length")
+#define CODE_DCM_PosteriorMitralValveP2LeafletScallopLength                DSRBasicCodedEntry("131206", "DCM", "Posterior mitral valve P2 leaflet scallop length")
+#define CODE_DCM_PosteriorMitralValveP3LeafletScallopLength                DSRBasicCodedEntry("131207", "DCM", "Posterior mitral valve P3 leaflet scallop length")
+#define CODE_DCM_TricuspidAnnulusArea                                      DSRBasicCodedEntry("131208", "DCM", "Tricuspid annulus area")
+#define CODE_DCM_TricuspidAnnulusAreaDiastolicSystolicRatio                DSRBasicCodedEntry("131209", "DCM", "Tricuspid annulus area diastolic systolic ratio")
+#define CODE_DCM_TricuspidAnnulusPerimeter                                 DSRBasicCodedEntry("131210", "DCM", "Tricuspid annulus perimeter")
+#define CODE_DCM_TricuspidValveCoaptationLength                            DSRBasicCodedEntry("131211", "DCM", "Tricuspid valve coaptation length")
+#define CODE_DCM_TricuspidValveMajorAxisDiastole                           DSRBasicCodedEntry("131212", "DCM", "Tricuspid valve major axis diastole")
+#define CODE_DCM_TricuspidValveMinorAxis                                   DSRBasicCodedEntry("131213", "DCM", "Tricuspid valve minor axis")
+#define CODE_DCM_TricuspidValveSphericityIndex                             DSRBasicCodedEntry("131214", "DCM", "Tricuspid valve sphericity index")
+#define CODE_DCM_TricuspidValveTentingHeight                               DSRBasicCodedEntry("131215", "DCM", "Tricuspid valve tenting height")
+#define CODE_DCM_TricuspidValveTentingVolume                               DSRBasicCodedEntry("131216", "DCM", "Tricuspid valve tenting volume")
+#define CODE_DCM_LeftAtrialAppendageClosureDeviceCircumference             DSRBasicCodedEntry("131217", "DCM", "Left atrial appendage closure device circumference")
+#define CODE_DCM_LeftAtrialAppendageClosureDeviceCompressionRatio          DSRBasicCodedEntry("131218", "DCM", "Left atrial appendage closure device compression ratio")
+#define CODE_DCM_LeftAtrialAppendageClosureDeviceDiameter                  DSRBasicCodedEntry("131219", "DCM", "Left atrial appendage closure device diameter")
+#define CODE_DCM_LeftAtrialAppendageClosureDeviceSize                      DSRBasicCodedEntry("131220", "DCM", "Left atrial appendage closure device size")
+#define CODE_DCM_LeftAtrialAppendageDepth                                  DSRBasicCodedEntry("131221", "DCM", "Left atrial appendage depth")
+#define CODE_DCM_LeftAtrialAppendageLandingZoneMajorAxis                   DSRBasicCodedEntry("131222", "DCM", "Left atrial appendage landing zone major axis")
+#define CODE_DCM_LeftAtrialAppendageMajorAxis                              DSRBasicCodedEntry("131223", "DCM", "Left atrial appendage major axis")
+#define CODE_DCM_LeftAtrialAppendageMinorAxis                              DSRBasicCodedEntry("131224", "DCM", "Left atrial appendage minor axis")
+#define CODE_DCM_LeftAtrialAppendageOstiumPerimeter                        DSRBasicCodedEntry("131225", "DCM", "Left atrial appendage ostium perimeter")
+#define CODE_DCM_FemaleTypical                                             DSRBasicCodedEntry("131230", "DCM", "Female-typical")
+#define CODE_DCM_MaleTypical                                               DSRBasicCodedEntry("131231", "DCM", "Male-typical")
+#define CODE_DCM_Specified                                                 DSRBasicCodedEntry("131232", "DCM", "Specified")
+#define CODE_DCM_SubjectSexParametersForClinicalUseCategory                DSRBasicCodedEntry("131233", "DCM", "Subject Sex Parameters for Clinical Use Category")
+#define CODE_DCM_SexParametersForClinicalUseCategoryComment                DSRBasicCodedEntry("131234", "DCM", "Sex Parameters for Clinical Use Category Comment")
+#define CODE_DCM_SexParametersForClinicalUseCategoryReference              DSRBasicCodedEntry("131235", "DCM", "Sex Parameters for Clinical Use Category Reference")
+#define CODE_DCM_VisualFieldKeyMeasurements                                DSRBasicCodedEntry("131240", "DCM", "Visual Field Key Measurements")
+#define CODE_DCM_OpticDiscKeyMeasurements                                  DSRBasicCodedEntry("131241", "DCM", "Optic Disc Key Measurements")
+#define CODE_DCM_CircumpapillaryRetinalNerveFiberLayerKeyMeasurements      DSRBasicCodedEntry("131242", "DCM", "Circumpapillary Retinal Nerve Fiber Layer Key Measurements")
+#define CODE_DCM_MacularThicknessKeyMeasurements                           DSRBasicCodedEntry("131243", "DCM", "Macular Thickness Key Measurements")
+#define CODE_DCM_GanglionCellLayerKeyMeasurements                          DSRBasicCodedEntry("131244", "DCM", "Ganglion Cell Layer Key Measurements")
+#define CODE_DCM_EndothelialCellCountKeyMeasurements                       DSRBasicCodedEntry("131245", "DCM", "Endothelial Cell Count Key Measurements")
+#define CODE_DCM_OphthalmicImageROIMeasurements                            DSRBasicCodedEntry("131246", "DCM", "Ophthalmic Image ROI Measurements")
+#define CODE_DCM_RepositionedROIOrGrid                                     DSRBasicCodedEntry("131247", "DCM", "Repositioned ROI or grid")
+#define CODE_DCM_VisualFieldGlobalDeviationFromNormal                      DSRBasicCodedEntry("131248", "DCM", "Visual Field Global Deviation from Normal")
+#define CODE_DCM_VisualFieldLocalizedDeviationFromNormal                   DSRBasicCodedEntry("131249", "DCM", "Visual Field Localized Deviation From Normal")
+#define CODE_DCM_FixationFalsePositiveRatio                                DSRBasicCodedEntry("131250", "DCM", "Fixation false positive ratio")
+#define CODE_DCM_FixationFalsePositivePercent                              DSRBasicCodedEntry("131251", "DCM", "Fixation false positive percent")
+#define CODE_DCM_FixationFalseNegativeRatio                                DSRBasicCodedEntry("131252", "DCM", "Fixation false negative ratio")
+#define CODE_DCM_FixationFalseNegativePercent                              DSRBasicCodedEntry("131253", "DCM", "Fixation false negative percent")
+#define CODE_DCM_FixationLossesRatio                                       DSRBasicCodedEntry("131254", "DCM", "Fixation losses ratio")
+#define CODE_DCM_AverageMacularThickness                                   DSRBasicCodedEntry("131255", "DCM", "Average macular thickness")
+#define CODE_DCM_CupToDiscAreaRatio                                        DSRBasicCodedEntry("131256", "DCM", "Cup to disc area ratio")
+#define CODE_DCM_CupToDiscRatioVertical                                    DSRBasicCodedEntry("131257", "DCM", "Cup to disc ratio vertical")
+#define CODE_DCM_CupToDiscRatioHorizontal                                  DSRBasicCodedEntry("131258", "DCM", "Cup to disc ratio horizontal")
+#define CODE_DCM_NeuroretinalRimArea                                       DSRBasicCodedEntry("131259", "DCM", "Neuroretinal rim area")
+#define CODE_DCM_NeuroretinalRimWidth                                      DSRBasicCodedEntry("131260", "DCM", "Neuroretinal rim width")
+#define CODE_DCM_OpticCupArea                                              DSRBasicCodedEntry("131261", "DCM", "Optic cup area")
+#define CODE_DCM_OpticDiscArea                                             DSRBasicCodedEntry("131262", "DCM", "Optic disc area")
+#define CODE_DCM_OpticCupVolume                                            DSRBasicCodedEntry("131263", "DCM", "Optic cup volume")
+#define CODE_DCM_RNFLAverageThickness                                      DSRBasicCodedEntry("131264", "DCM", "RNFL average thickness")
+#define CODE_DCM_RNFLInferiorSectorThickness                               DSRBasicCodedEntry("131265", "DCM", "RNFL inferior sector thickness")
+#define CODE_DCM_RNFLSuperiorSectorThickness                               DSRBasicCodedEntry("131266", "DCM", "RNFL superior sector thickness")
+#define CODE_DCM_RNFLTemporalSectorThickness                               DSRBasicCodedEntry("131267", "DCM", "RNFL temporal sector thickness")
+#define CODE_DCM_RNFLNasalSectorThickness                                  DSRBasicCodedEntry("131268", "DCM", "RNFL nasal sector thickness")
+#define CODE_DCM_RNFLNasalSuperiorSectorThickness                          DSRBasicCodedEntry("131269", "DCM", "RNFL nasal-superior sector thickness")
+#define CODE_DCM_RNFLNasalInferiorSectorThickness                          DSRBasicCodedEntry("131270", "DCM", "RNFL nasal-inferior sector thickness")
+#define CODE_DCM_RNFLTemporalInferiorSectorThickness                       DSRBasicCodedEntry("131271", "DCM", "RNFL temporal-inferior sector thickness")
+#define CODE_DCM_RNFLTemporalSuperiorSectorThickness                       DSRBasicCodedEntry("131272", "DCM", "RNFL temporal-superior sector thickness")
+#define CODE_DCM_RetinalNerveFiberLayerSymmetry                            DSRBasicCodedEntry("131273", "DCM", "Retinal nerve fiber layer symmetry")
+#define CODE_DCM_RetinalROIWidth                                           DSRBasicCodedEntry("131274", "DCM", "Retinal ROI width")
+#define CODE_DCM_RetinalROIHeight                                          DSRBasicCodedEntry("131275", "DCM", "Retinal ROI height")
+#define CODE_DCM_RNFLClockfacePosition1Thickness                           DSRBasicCodedEntry("131276", "DCM", "RNFL clockface position 1 thickness")
+#define CODE_DCM_RNFLClockfacePosition2Thickness                           DSRBasicCodedEntry("131277", "DCM", "RNFL clockface position 2 thickness")
+#define CODE_DCM_RNFLClockfacePosition3Thickness                           DSRBasicCodedEntry("131278", "DCM", "RNFL clockface position 3 thickness")
+#define CODE_DCM_RNFLClockfacePosition4Thickness                           DSRBasicCodedEntry("131279", "DCM", "RNFL clockface position 4 thickness")
+#define CODE_DCM_RNFLClockfacePosition5Thickness                           DSRBasicCodedEntry("131280", "DCM", "RNFL clockface position 5 thickness")
+#define CODE_DCM_RNFLClockfacePosition6Thickness                           DSRBasicCodedEntry("131281", "DCM", "RNFL clockface position 6 thickness")
+#define CODE_DCM_RNFLClockfacePosition7Thickness                           DSRBasicCodedEntry("131282", "DCM", "RNFL clockface position 7 thickness")
+#define CODE_DCM_RNFLClockfacePosition8Thickness                           DSRBasicCodedEntry("131283", "DCM", "RNFL clockface position 8 thickness")
+#define CODE_DCM_RNFLClockfacePosition9Thickness                           DSRBasicCodedEntry("131284", "DCM", "RNFL clockface position 9 thickness")
+#define CODE_DCM_RNFLClockfacePosition10Thickness                          DSRBasicCodedEntry("131285", "DCM", "RNFL clockface position 10 thickness")
+#define CODE_DCM_RNFLClockfacePosition11Thickness                          DSRBasicCodedEntry("131286", "DCM", "RNFL clockface position 11 thickness")
+#define CODE_DCM_RNFLClockfacePosition12Thickness                          DSRBasicCodedEntry("131287", "DCM", "RNFL clockface position 12 thickness")
+#define CODE_DCM_AverageGanglionCellThickness                              DSRBasicCodedEntry("131288", "DCM", "Average ganglion cell thickness")
+#define CODE_DCM_MinimumGanglionCellThickness                              DSRBasicCodedEntry("131289", "DCM", "Minimum ganglion cell thickness")
+#define CODE_DCM_AverageGanglionCellThicknessSuperiorSector                DSRBasicCodedEntry("131290", "DCM", "Average ganglion cell thickness superior sector")
+#define CODE_DCM_AverageGanglionCellThicknessNasalSuperiorSector           DSRBasicCodedEntry("131291", "DCM", "Average ganglion cell thickness nasal-superior sector")
+#define CODE_DCM_AverageGanglionCellThicknessNasalSector                   DSRBasicCodedEntry("131292", "DCM", "Average ganglion cell thickness nasal sector")
+#define CODE_DCM_AverageGanglionCellThicknessNasalInferiorSector           DSRBasicCodedEntry("131293", "DCM", "Average ganglion cell thickness nasal-inferior sector")
+#define CODE_DCM_AverageGanglionCellThicknessInferiorSector                DSRBasicCodedEntry("131294", "DCM", "Average ganglion cell thickness inferior sector")
+#define CODE_DCM_AverageGanglionCellThicknessTemporalInferiorSector        DSRBasicCodedEntry("131295", "DCM", "Average ganglion cell thickness temporal-inferior sector")
+#define CODE_DCM_AverageGanglionCellThicknessTemporalSector                DSRBasicCodedEntry("131296", "DCM", "Average ganglion cell thickness temporal sector")
+#define CODE_DCM_AverageGanglionCellThicknessTemporalSuperiorSector        DSRBasicCodedEntry("131297", "DCM", "Average ganglion cell thickness temporal-superior sector")
+#define CODE_DCM_AverageGanglionCellThicknessInPosteriorPoleGrid           DSRBasicCodedEntry("131298", "DCM", "Average ganglion cell thickness in posterior pole grid")
+#define CODE_DCM_GanglionCellAndInnerPlexiformLayers                       DSRBasicCodedEntry("131299", "DCM", "Ganglion cell and inner plexiform layers")
+#define CODE_DCM_GanglionCellComplex                                       DSRBasicCodedEntry("131300", "DCM", "Ganglion cell complex")
+#define CODE_DCM_SemicircularSectors                                       DSRBasicCodedEntry("131301", "DCM", "Semicircular sectors")
+#define CODE_DCM_QuadrantSectors                                           DSRBasicCodedEntry("131302", "DCM", "Quadrant sectors")
+#define CODE_DCM_SNITRectangularSectors                                    DSRBasicCodedEntry("131303", "DCM", "SNIT rectangular sectors")
+#define CODE_DCM_EllipticalAnnulusSectors                                  DSRBasicCodedEntry("131304", "DCM", "Elliptical annulus sectors")
+#define CODE_DCM_GarwayHeathSectors                                        DSRBasicCodedEntry("131305", "DCM", "Garway-Heath sectors")
+#define CODE_DCM_QuadrantOctantSectors                                     DSRBasicCodedEntry("131306", "DCM", "Quadrant-octant sectors")
+#define CODE_DCM_PosteriorPole8x8Grid                                      DSRBasicCodedEntry("131307", "DCM", "Posterior pole 8x8 grid")
+#define CODE_DCM_RNFLClockfaceMethod                                       DSRBasicCodedEntry("131308", "DCM", "RNFL Clockface Method")
+#define CODE_DCM_EndothelialCellDensity                                    DSRBasicCodedEntry("131309", "DCM", "Endothelial cell density")
+#define CODE_DCM_GeographicAtrophyArea                                     DSRBasicCodedEntry("131310", "DCM", "Geographic atrophy area")
+#define CODE_DCM_PlanMeetsPrescription                                     DSRBasicCodedEntry("131315", "DCM", "Plan meets prescription")
+#define CODE_DCM_PlanQAPassed                                              DSRBasicCodedEntry("131316", "DCM", "Plan QA passed")
+#define CODE_DCM_LinearBoltzmannTransportEquation                          DSRBasicCodedEntry("131320", "DCM", "Linear Boltzmann Transport Equation")
+#define CODE_DCM_PencilBeamConvolution                                     DSRBasicCodedEntry("131321", "DCM", "Pencil Beam Convolution")
+#define CODE_DCM_TMRAndOARRatios                                           DSRBasicCodedEntry("131322", "DCM", "TMR and OAR Ratios")
+#define CODE_DCM_AAPMTG43                                                  DSRBasicCodedEntry("131323", "DCM", "AAPM TG-43")
+#define CODE_DCM_ConvolutionSuperposition                                  DSRBasicCodedEntry("131324", "DCM", "Convolution Superposition")
+#define CODE_DCM_NumberOfHistories                                         DSRBasicCodedEntry("131325", "DCM", "Number of Histories")
+#define CODE_DCM_AcceptableUncertaintyInDoseResult                         DSRBasicCodedEntry("131326", "DCM", "Acceptable Uncertainty in Dose Result")
+#define CODE_DCM_CalibrationIntendedDoseIndex                              DSRBasicCodedEntry("131330", "DCM", "Calibration Intended Dose Index")
+#define CODE_DCM_CalibrationIntendedAcquisitionProtocol                    DSRBasicCodedEntry("131331", "DCM", "Calibration Intended Acquisition Protocol")
+#define CODE_DCM_UltrasoundAttenuationImaging                              DSRBasicCodedEntry("131340", "DCM", "Ultrasound Attenuation Imaging")
+#define CODE_DCM_UltrasoundAttenuationCoefficient                          DSRBasicCodedEntry("131341", "DCM", "Ultrasound Attenuation Coefficient")
+#define CODE_DCM_MeanUltrasoundAttenuationCoefficient                      DSRBasicCodedEntry("131342", "DCM", "Mean Ultrasound Attenuation Coefficient")
+#define CODE_DCM_MedianUltrasoundAttenuationCoefficient                    DSRBasicCodedEntry("131343", "DCM", "Median Ultrasound Attenuation Coefficient")
+#define CODE_DCM_StandardDeviationOfUltrasoundAttenuationCoefficient       DSRBasicCodedEntry("131344", "DCM", "Standard Deviation of Ultrasound Attenuation Coefficient")
+#define CODE_DCM_InterquartileRangeOfUltrasoundAttenuationCoefficient      DSRBasicCodedEntry("131345", "DCM", "Interquartile Range of Ultrasound Attenuation Coefficient")
+#define CODE_DCM_InterquartileRangeToMedianRatioOfUltrasoundAttenCoeff     DSRBasicCodedEntry("131346", "DCM", "Interquartile Range to Median Ratio of Ultrasound Atten Coeff")
+#define CODE_DCM_CardiacAxisAngle                                          DSRBasicCodedEntry("131350", "DCM", "Cardiac Axis Angle")
+#define CODE_DCM_DVSWavePeakVelocity                                       DSRBasicCodedEntry("131351", "DCM", "DV S-wave peak velocity")
+#define CODE_DCM_DVAWavePeakVelocity                                       DSRBasicCodedEntry("131352", "DCM", "DV a-wave peak velocity")
+#define CODE_DCM_DVPreloadIndex                                            DSRBasicCodedEntry("131353", "DCM", "DV preload index")
+#define CODE_DCM_DVSA                                                      DSRBasicCodedEntry("131354", "DCM", "DV S/a")
+#define CODE_DCM_RejectionWithdrawn                                        DSRBasicCodedEntry("131360", "DCM", "Rejection Withdrawn")
+#define CODE_DCM_FetalAnatomySurvey                                        DSRBasicCodedEntry("131370", "DCM", "Fetal Anatomy Survey")
+#define CODE_DCM_AbdominalAttachmentOfUmbilicalCord                        DSRBasicCodedEntry("131371", "DCM", "Abdominal attachment of umbilical cord")
+#define CODE_DCM_RetronasalTriangle                                        DSRBasicCodedEntry("131372", "DCM", "Retronasal triangle")
+#define CODE_DCM_MidsagittalFacialProfile                                  DSRBasicCodedEntry("131373", "DCM", "Midsagittal facial profile")
+#define CODE_DCM_CardiacAxis                                               DSRBasicCodedEntry("131374", "DCM", "Cardiac axis")
+#define CODE_DCM_JugularLymphaticSac                                       DSRBasicCodedEntry("131375", "DCM", "Jugular lymphatic sac")
+#define CODE_DCM_TransthalamicCoronalView                                  DSRBasicCodedEntry("131376", "DCM", "Transthalamic coronal view")
+#define CODE_DCM_MidsagittalView                                           DSRBasicCodedEntry("131377", "DCM", "Midsagittal view")
+#define CODE_DCM_HighShortAxisView                                         DSRBasicCodedEntry("131378", "DCM", "High short axis view")
+#define CODE_DCM_AntegradeDuctusVenosus                                    DSRBasicCodedEntry("131379", "DCM", "Antegrade ductus venosus")
+#define CODE_DCM_ISUOG1stTrimester2023                                     DSRBasicCodedEntry("131380", "DCM", "ISUOG 1st Trimester 2023")
+#define CODE_DCM_ISUOG2ndTrimester2022                                     DSRBasicCodedEntry("131381", "DCM", "ISUOG 2nd Trimester 2022")
+#define CODE_DCM_ISUOG3rdTrimester2024                                     DSRBasicCodedEntry("131382", "DCM", "ISUOG 3rd Trimester 2024")
+#define CODE_DCM_JSUMFetalMorphology2021                                   DSRBasicCodedEntry("131383", "DCM", "JSUM Fetal Morphology 2021")
+#define CODE_DCM_JDMSFetalAnatomy2014                                      DSRBasicCodedEntry("131384", "DCM", "JDMS Fetal Anatomy 2014")
 
 #endif
index c62600098a56eb662f17b90bfd1f598d8ed00c37..a429e757ac58d17d5e23be0a077e43b4d10b0908 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file with NCI Thesaurus Code Definitions (Coding Scheme "NCIt")
  *
- *  Generated automatically from DICOM PS 3.16-2024e
- *  File created on 2024-11-16 10:17:31 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 11:52:23 by J. Riesmeier
  *
  */
 
@@ -34,7 +34,7 @@
  *  code definitions  *
  *--------------------*/
 
-// total number of codes: 51
+// total number of codes: 61
 // - retired: 0
 // - no name: 0
 // - not unique: 0
 #define CODE_NCIt_Sarcosine_C11                                            DSRBasicCodedEntry("C122684", "NCIt", "Sarcosine C^11^")
 #define CODE_NCIt_IrreversibleElectroporation                              DSRBasicCodedEntry("C131483", "NCIt", "Irreversible electroporation")
 #define CODE_NCIt_4Kscore                                                  DSRBasicCodedEntry("C142184", "NCIt", "4Kscore")
+#define CODE_NCIt_Pembrolizumab_89Zr                                       DSRBasicCodedEntry("C148167", "NCIt", "Pembrolizumab ^89^Zr")
 #define CODE_NCIt_SoftTissueSarcoma_excludingRhabdomyosarcoma              DSRBasicCodedEntry("C148457", "NCIt", "Soft tissue sarcoma, excluding rhabdomyosarcoma")
 #define CODE_NCIt_Cryoablation                                             DSRBasicCodedEntry("C15215", "NCIt", "Cryoablation")
+#define CODE_NCIt_PAXgeneTissueSystem                                      DSRBasicCodedEntry("C185113", "NCIt", "PAXgene Tissue System")
 #define CODE_NCIt_166Holmium                                               DSRBasicCodedEntry("C1943", "NCIt", "^166^Holmium")
 #define CODE_NCIt_MouseMammaryFatPad                                       DSRBasicCodedEntry("C22550", "NCIt", "Mouse mammary fat pad")
 #define CODE_NCIt_Middle                                                   DSRBasicCodedEntry("C25569", "NCIt", "Middle")
 #define CODE_NCIt_Experience                                               DSRBasicCodedEntry("C54627", "NCIt", "Experience")
 #define CODE_NCIt_Reviewer                                                 DSRBasicCodedEntry("C54634", "NCIt", "Reviewer")
 #define CODE_NCIt_Ion                                                      DSRBasicCodedEntry("C597", "NCIt", "Ion")
+#define CODE_NCIt_FluoroazomycinArabinoside_F18                            DSRBasicCodedEntry("C62520", "NCIt", "Fluoroazomycin arabinoside F^18^")
 #define CODE_NCIt_AdLibitum                                                DSRBasicCodedEntry("C64636", "NCIt", "ad libitum")
 #define CODE_NCIt_ActivitySession                                          DSRBasicCodedEntry("C67447", "NCIt", "Activity Session")
 #define CODE_NCIt_FocusedUltrasoundAblation                                DSRBasicCodedEntry("C68681", "NCIt", "Focused ultrasound ablation")
 #define CODE_NCIt_UnitConversionFactor                                     DSRBasicCodedEntry("C70774", "NCIt", "Unit Conversion Factor")
 #define CODE_NCIt_MedicalProductExpirationDate                             DSRBasicCodedEntry("C70854", "NCIt", "Medical Product Expiration Date")
+#define CODE_NCIt_FitzpatrickSkinTypeI                                     DSRBasicCodedEntry("C74569", "NCIt", "Fitzpatrick Skin Type I")
+#define CODE_NCIt_FitzpatrickSkinTypeII                                    DSRBasicCodedEntry("C74570", "NCIt", "Fitzpatrick Skin Type II")
+#define CODE_NCIt_FitzpatrickSkinTypeIII                                   DSRBasicCodedEntry("C74571", "NCIt", "Fitzpatrick Skin Type III")
+#define CODE_NCIt_FitzpatrickSkinTypeIV                                    DSRBasicCodedEntry("C74572", "NCIt", "Fitzpatrick Skin Type IV")
+#define CODE_NCIt_FitzpatrickSkinTypeV                                     DSRBasicCodedEntry("C74573", "NCIt", "Fitzpatrick Skin Type V")
+#define CODE_NCIt_FitzpatrickSkinTypeVI                                    DSRBasicCodedEntry("C74574", "NCIt", "Fitzpatrick Skin Type VI")
 #define CODE_NCIt_CardiotonicAgent                                         DSRBasicCodedEntry("C78322", "NCIt", "Cardiotonic agent")
 #define CODE_NCIt_NonEnhancingLesion                                       DSRBasicCodedEntry("C81175", "NCIt", "Non-Enhancing Lesion")
 #define CODE_NCIt_ImagingRegionOfInterest                                  DSRBasicCodedEntry("C85402", "NCIt", "Imaging Region of Interest")
 #define CODE_NCIt_HousingHumidity                                          DSRBasicCodedEntry("C90395", "NCIt", "Housing humidity")
 #define CODE_NCIt_LightCycle                                               DSRBasicCodedEntry("C90419", "NCIt", "Light cycle")
 #define CODE_NCIt_WaterDelivery                                            DSRBasicCodedEntry("C90486", "NCIt", "Water delivery")
+#define CODE_NCIt_2Thymidine_C11                                           DSRBasicCodedEntry("C90936", "NCIt", "2-Thymidine C^11^")
 #define CODE_NCIt_Dosimetrist                                              DSRBasicCodedEntry("C93176", "NCIt", "Dosimetrist")
 #define CODE_NCIt_Abnormality                                              DSRBasicCodedEntry("C9440", "NCIt", "Abnormality")
 #define CODE_NCIt_ReferenceRegion                                          DSRBasicCodedEntry("C94970", "NCIt", "Reference Region")
index 49b184db9a9ded4b40c92b3b3b8a2560f34fd69f..2e8cd36a495d7da31fbc642b0632fd77abc5dfc2 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Header file with UMLS Code Definitions (Coding Scheme "UMLS")
  *
- *  Generated automatically from DICOM PS 3.16-2024e
- *  File created on 2024-11-16 10:17:31 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 11:52:22 by J. Riesmeier
  *
  */
 
@@ -34,7 +34,7 @@
  *  code definitions  *
  *--------------------*/
 
-// total number of codes: 51
+// total number of codes: 60
 // - retired: 0
 // - no name: 0
 // - not unique: 0
@@ -68,6 +68,8 @@
 #define CODE_UMLS_Duration                                                 DSRBasicCodedEntry("C0449238", "UMLS", "Duration")
 #define CODE_UMLS_InfantOfMotherWithGestationalDiabetes                    DSRBasicCodedEntry("C0456029", "UMLS", "Infant of mother with gestational diabetes")
 #define CODE_UMLS_CoefficientOfVariance                                    DSRBasicCodedEntry("C0681921", "UMLS", "Coefficient of Variance")
+#define CODE_UMLS_HeartSize                                                DSRBasicCodedEntry("C0744689", "UMLS", "Heart size")
+#define CODE_UMLS_PercutaneousClosureOfAtrialSeptalDefect                  DSRBasicCodedEntry("C0844084", "UMLS", "Percutaneous closure of atrial septal defect")
 #define CODE_UMLS_ManufacturerName                                         DSRBasicCodedEntry("C0947322", "UMLS", "Manufacturer Name")
 #define CODE_UMLS_Intern                                                   DSRBasicCodedEntry("C1144859", "UMLS", "Intern")
 #define CODE_UMLS_ConsultingPhysician                                      DSRBasicCodedEntry("C1441532", "UMLS", "Consulting Physician")
 #define CODE_UMLS_Referring                                                DSRBasicCodedEntry("C1709880", "UMLS", "Referring")
 #define CODE_UMLS_Variance                                                 DSRBasicCodedEntry("C1711260", "UMLS", "Variance")
 #define CODE_UMLS_Sonographer                                              DSRBasicCodedEntry("C1954848", "UMLS", "Sonographer")
+#define CODE_UMLS_AorticSinusOfValsalvaDiameter                            DSRBasicCodedEntry("C2059455", "UMLS", "Aortic sinus of valsalva diameter")
+#define CODE_UMLS_AorticAnnulusArea                                        DSRBasicCodedEntry("C2059685", "UMLS", "Aortic annulus area")
 #define CODE_UMLS_MobileSkinLesion                                         DSRBasicCodedEntry("C2071496", "UMLS", "Mobile skin lesion")
 #define CODE_UMLS_Neuroradiology                                           DSRBasicCodedEntry("C2183225", "UMLS", "Neuroradiology")
 #define CODE_UMLS_InverseRatioVentilation                                  DSRBasicCodedEntry("C2223982", "UMLS", "Inverse ratio ventilation")
 #define CODE_UMLS_RootMeanSquare                                           DSRBasicCodedEntry("C2347976", "UMLS", "Root Mean Square")
 #define CODE_UMLS_TimePoint                                                DSRBasicCodedEntry("C2348792", "UMLS", "Time Point")
 #define CODE_UMLS_Edotreotide_Ga68                                         DSRBasicCodedEntry("C2713594", "UMLS", "Edotreotide Ga^68^")
+#define CODE_UMLS_ImplantationOfMitralValveLeafletClip                     DSRBasicCodedEntry("C2921037", "UMLS", "Implantation of mitral valve leaflet clip")
 #define CODE_UMLS_FluoropropylDihydrotetrabenazine_F18                     DSRBasicCodedEntry("C2934038", "UMLS", "Fluoropropyl-dihydrotetrabenazine F^18^")
 #define CODE_UMLS_ISO1_F18                                                 DSRBasicCodedEntry("C2981788", "UMLS", "ISO-1 F^18^")
 #define CODE_UMLS_RadiationPhysicist                                       DSRBasicCodedEntry("C2985483", "UMLS", "Radiation Physicist")
+#define CODE_UMLS_LeftAtrialAppendageOcclusion                             DSRBasicCodedEntry("C3275093", "UMLS", "Left atrial appendage occlusion")
+#define CODE_UMLS_IntoleranceToAnticoagulation                             DSRBasicCodedEntry("C3468959", "UMLS", "Intolerance to anticoagulation")
 #define CODE_UMLS_Pretreatment                                             DSRBasicCodedEntry("C3539075", "UMLS", "Pretreatment")
 #define CODE_UMLS_DistalPhalanx                                            DSRBasicCodedEntry("C3669027", "UMLS", "Distal phalanx")
 #define CODE_UMLS_RoomAir                                                  DSRBasicCodedEntry("C3846005", "UMLS", "Room air")
+#define CODE_UMLS_LeftAtrialDilation                                       DSRBasicCodedEntry("C4015487", "UMLS", "Left atrial dilation")
 #define CODE_UMLS_THK5351_F18                                              DSRBasicCodedEntry("C4279748", "UMLS", "THK5351 F^18^")
 #define CODE_UMLS_MK6240_F18                                               DSRBasicCodedEntry("C4506764", "UMLS", "MK-6240 F^18^")
 #define CODE_UMLS_UCBJ_C11                                                 DSRBasicCodedEntry("C4506788", "UMLS", "UCB-J C^11^")
 #define CODE_UMLS_THK5317_F18                                              DSRBasicCodedEntry("C4550127", "UMLS", "THK5317 F^18^")
+#define CODE_UMLS_PI2620_F18                                               DSRBasicCodedEntry("C5433257", "UMLS", "PI-2620 F^18^")
 #define CODE_UMLS_MiddleEasternOrNorthAfrican                              DSRBasicCodedEntry("C5690844", "UMLS", "Middle Eastern or North African")
 
 #endif
index 24512fc7c314b41a6865d302b8261d53ddde93a1..4df8b73e82ef9d1a9651ba6db449dd38cf997b21 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -179,6 +179,10 @@ class DCMTK_DCMSR_EXPORT DSRCompositeReferenceValue
      *                       Value is increased automatically by 1 after a new entry has been added.
      *  @param  flags        flag used to customize the output (see DSRTypes::HF_xxx)
      *  @param  urlPrefix    optional URL prefix used for hyperlink to referenced composite object
+     ** @note Please note that using parameter 'urlPrefix' can lead to security issues, as an
+     *        attacker could misuse it to potentially inject dangerous content into the HTML/XHTML
+     *        output.  The value of this parameter is not checked.  This is also true for derived
+     *        classes.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
index a82c56c145cd7fa4fb0611049694ae91b31b4b41..cf9fa05a6002a482488d2be2baeda3c59cd796ef 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2016, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -86,6 +86,14 @@ class DCMTK_DCMSR_EXPORT DSRContextGroup
         return MappingResource;
     }
 
+    /** get context group keyword
+     ** @return keyword of the context group (might be empty)
+     */
+    inline const OFString &getKeyword() const
+    {
+        return Keyword;
+    }
+
     /** get context group version (optional)
      ** @return version of the context group (might be empty)
      */
@@ -203,6 +211,7 @@ class DCMTK_DCMSR_EXPORT DSRContextGroup
     /** constructor
      ** @param  contextIdentifier    identifier of the context group
      *  @param  mappingResource      mapping resource that defines the context group
+     *  @param  contextGroupKeyword  keyword of the context group (optional)
      *  @param  contextGroupVersion  version of the context group (optional)
      *  @param  contextGroupUID      unique identifier of the context group (optional)
      *  @param  selectedValue        coded entry to be selected as the current value
@@ -210,6 +219,7 @@ class DCMTK_DCMSR_EXPORT DSRContextGroup
      */
     DSRContextGroup(const OFString &contextIdentifier,
                     const OFString &mappingResource,
+                    const OFString &contextGroupKeyword = "",
                     const OFString &contextGroupVersion = "",
                     const OFString &contextGroupUID = "",
                     const DSRCodedEntryValue &selectedValue = DSRCodedEntryValue());
@@ -265,6 +275,8 @@ class DCMTK_DCMSR_EXPORT DSRContextGroup
     const OFString Identifier;
     /// mapping resource (VR=CS, mandatory)
     const OFString MappingResource;
+    /// context group keyword (optional)
+    const OFString Keyword;
     /// context group version (VR=DT, optional)
     const OFString Version;
     /// context group UID (VR=UI, optional)
index b670f16b2d9abc7db2cd7f21f34398e4aafc72a6..5feeb411f6583cae5c7f8afcc700eb43ac508a01 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -32,6 +32,7 @@
 #include "dcmtk/dcmsr/dsrrefin.h"
 #include "dcmtk/dcmsr/dsrcsidl.h"
 
+#include "dcmtk/dcmdata/dcvras.h"
 #include "dcmtk/dcmdata/dcvrcs.h"
 #include "dcmtk/dcmdata/dcvrda.h"
 #include "dcmtk/dcmdata/dcvrds.h"
@@ -200,6 +201,10 @@ class DCMTK_DCMSR_EXPORT DSRDocument
      *                      objects.  If NULL, the default URL prefix is used, which is
      *                      defined by DEFAULT_HTML_HYPERLINK_PREFIX_FOR_COMPOSITE_OBJECTS
      *                      (http://localhost/dicom.cgi).
+     ** @note Please note that using the parameter 'styleSheet' or 'urlPrefix' can lead to
+     *        security issues, as an attacker could misuse them to potentially inject dangerous
+     *        content into the HTML/XHTML output.  The values passed to these parameters are not
+     *        checked, neither the URL and prefix nor the content of the specified CSS file.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &stream,
@@ -532,6 +537,14 @@ class DCMTK_DCMSR_EXPORT DSRDocument
     virtual OFCondition getPatientSex(OFString &value,
                                       const signed long pos = 0) const;
 
+    /** get patient's age
+     ** @param  value  reference to variable in which the value should be stored
+     *  @param  pos    index of the value to get (0..vm-1), -1 for all components
+     ** @return status, EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition getPatientAge(OFString &value,
+                                      const signed long pos = 0) const;
+
     /** get patient's size
      ** @param  value  reference to variable in which the value should be stored
      *  @param  pos    index of the value to get (0..vm-1), -1 for all components
@@ -808,6 +821,14 @@ class DCMTK_DCMSR_EXPORT DSRDocument
     virtual OFCondition setPatientSex(const OFString &value,
                                       const OFBool check = OFTrue);
 
+    /** set patient's age
+     ** @param  value  value to be set (single value only) or "" for no value
+     *  @param  check  check 'value' for conformance with VR (AS) and VM (1) if enabled
+     ** @return status, EC_Normal if successful, an error code otherwise
+     */
+    virtual OFCondition setPatientAge(const OFString &value,
+                                      const OFBool check = OFTrue);
+
     /** set patient's size
      ** @param  value  value to be set (single value only) or "" for no value
      *  @param  check  check 'value' for conformance with VR (DS) and VM (1) if enabled
@@ -1064,14 +1085,14 @@ class DCMTK_DCMSR_EXPORT DSRDocument
 
     /** create a new document.
      *  A new SOP instance is only created if the current document type was valid/supported.
-     *  Please note that the current document is deleted (cleared).
+     *  Please note that the current document is deleted (cleared) by this method.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition createNewDocument();
 
     /** create a new document of the specified type.
      *  A new SOP instance is only created if the current document type was valid/supported.
-     *  Please note that the current document is deleted by this method.
+     *  Please note that the current document is deleted (cleared) by this method.
      ** @param  documentType  type of the new SR document (see DSRTypes::E_DocumentType)
      ** @return status, EC_Normal if successful, an error code otherwise
      */
@@ -1408,6 +1429,8 @@ class DCMTK_DCMSR_EXPORT DSRDocument
 
     // --- Patient Study Module (U) ---
 
+    /// Patient's Age: (AS, 1, 3)
+    DcmAgeString        PatientAge;
     /// Patient's Size: (DS, 1, 3)
     DcmDecimalString    PatientSize;
     /// Patient's Weight: (DS, 1, 3)
index a17919bc144ddf6bc0113df5899b4ac0aea502fe..a9f14c0dc7e19f94f311365207129a1930b96dbb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -227,6 +227,10 @@ class DCMTK_DCMSR_EXPORT DSRDocumentTreeNode
      *  @param  flags         flag used to customize the output (see DSRTypes::HF_xxx)
      *  @param  urlPrefix     optional URL prefix used for hyperlinks to referenced composite
      *                        objects.  If NULL, the default URL prefix is used.
+     ** @note Please note that using parameter 'urlPrefix' can lead to security issues, as an
+     *        attacker could misuse it to potentially inject dangerous content into the HTML/XHTML
+     *        output.  The value of this parameter is not checked.  This is also true for derived
+     *        classes.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
index 354bece5a1220ea03f49159694e2729507ea2d4d..e0ad77ebddad42103f6bc369e3faf9c1a2722a05 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -139,6 +139,9 @@ class DCMTK_DCMSR_EXPORT DSRDocumentTree
      *  @param  flags        optional flag used to customize the output (see DSRTypes::HF_xxx)
      *  @param  urlPrefix    optional URL prefix used for hyperlinks to referenced composite
      *                       objects.  If NULL, the default URL prefix is used.
+     ** @note Please note that using parameter 'urlPrefix' can lead to security issues, as an
+     *        attacker could misuse it to potentially inject dangerous content into the HTML/XHTML
+     *        output.  The value of this parameter is not checked.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
index 8fcf4ed6e654795bafc8f586c6e92c2a5310ffc9..8f9873f1109ad7b1c40355f82404b00d2eb66c01 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -161,12 +161,19 @@ class DCMTK_DCMSR_EXPORT DSRImageReferenceValue
      */
     virtual OFBool isSegmentation() const;
 
+    /** check whether an icon image is associated with this image reference.
+     *  This method does not check whether the icon image is valid.
+     ** @return OFTrue if image reference has an icon image, OFFalse otherwise
+     */
+    virtual OFBool hasIconImage() const;
+
     /** print image reference.
      *  The output of a typical image reference value looks like this: (CT image,"1.2.3") or
      *  (CT image,"1.2.3"),(GSPS,"1.2.3.4") if a presentation state is present.
      *  If the SOP class UID is unknown, the UID is printed instead of the related name.
      *  Also, the list of referenced frame/segment numbers is shown, but not the two UIDs of
-     *  the real world value mapping object (if referenced).
+     *  the real world value mapping object (if referenced).  The optional icon image is never
+     *  shown.
      ** @param  stream  output stream to which the image reference value should be printed
      *  @param  flags   flag used to customize the output (see DSRTypes::PF_xxx)
      ** @return status, EC_Normal if successful, an error code otherwise
@@ -201,6 +208,10 @@ class DCMTK_DCMSR_EXPORT DSRImageReferenceValue
      *                       has been added.
      *  @param  flags        flag used to customize the output (see DSRTypes::HF_xxx)
      *  @param  urlPrefix    optional URL prefix used for hyperlink to referenced composite object
+     ** @note Please note that using parameter 'urlPrefix' can lead to security issues, as an
+     *        attacker could misuse it to potentially inject dangerous content into the HTML/XHTML
+     *        output.  The value of this parameter is not checked.  This is also true for derived
+     *        classes.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
@@ -504,6 +515,12 @@ class DCMTK_DCMSR_EXPORT DSRImageReferenceValue
      */
     OFCondition checkCurrentValue(const OFBool reportWarnings = OFFalse) const;
 
+    /** copy the given icon image to replace the currently stored one.
+     *  The currently stored icon image is always deleted first.
+     *  @param  image  pointer to the icon image to be copied (if not NULL)
+     */
+    void copyIconImage(DicomImage *image);
+
 
   private:
 
index ba1ecc9a0cbad1e99091c1a84568617206343a41..7d2f27715191051554534445a2af458e37a30e55 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -121,7 +121,7 @@ class DSRIODConstraintChecker;
  *  These error codes can be used in addition to the general purpose
  *  codes defined in module dcmdata.
  */
-//@{
+///@{
 
 /// error: the document type (SOP class UID) is unknown or not supported
 extern DCMTK_DCMSR_EXPORT const OFConditionConst SR_EC_UnknownDocumentType;
@@ -225,7 +225,7 @@ extern DCMTK_DCMSR_EXPORT const OFConditionConst SR_EC_InvalidTemplateStructure;
 /// error: cannot process document tree with included templates
 extern DCMTK_DCMSR_EXPORT const OFConditionConst SR_EC_CannotProcessIncludedTemplates;
 
-//@}
+///@}
 
 
 /*---------------------*
@@ -248,7 +248,7 @@ class DCMTK_DCMSR_EXPORT DSRTypes
      *  These flags can be combined and passed to the read() methods.
      *  The 'shortcut' flags can be used for common combinations.
      */
-    //@{
+    ///@{
 
     /// read digital signatures from dataset
     static const size_t RF_readDigitalSignatures;
@@ -270,7 +270,7 @@ class DCMTK_DCMSR_EXPORT DSRTypes
 
     /// show the currently processed content item (e.g. "1.2.3")
     static const size_t RF_showCurrentlyProcessedItem;
-    //@}
+    ///@}
 
 
     /** @name renderHTML() flags
@@ -278,7 +278,7 @@ class DCMTK_DCMSR_EXPORT DSRTypes
      *  Please note that only the 'external' flags can be used from outside
      *  this library.  The 'shortcut' flags can be used for common combinations.
      */
-    //@{
+    ///@{
 
     /// external: never expand child nodes inline
     static const size_t HF_neverExpandChildrenInline;
@@ -351,14 +351,14 @@ class DCMTK_DCMSR_EXPORT DSRTypes
 
     /// shortcut: filter all flags that are only used internally
     static const size_t HF_internalUseOnly;
-    //@}
+    ///@}
 
 
     /** @name read/writeXML() flags
      *  These flags can be combined and passed to the read/writeXML() methods.
      *  The 'shortcut' flags can be used for common combinations.
      */
-    //@{
+    ///@{
 
     /// write: write all tags even if their value is empty
     static const size_t XF_writeEmptyTags;
@@ -401,14 +401,14 @@ class DCMTK_DCMSR_EXPORT DSRTypes
 
     /// shortcut: combines all XF_xxxAsAttribute write flags (see above)
     static const size_t XF_encodeEverythingAsAttribute;
-    //@}
+    ///@}
 
 
     /** @name print() flags
      *  These flags can be combined and passed to the print() methods.
      *  The 'shortcut' flags can be used for common combinations.
      */
-    //@{
+    ///@{
 
     /// print item position ("1.2.3") instead of line indentation
     static const size_t PF_printItemPosition;
@@ -460,13 +460,13 @@ class DCMTK_DCMSR_EXPORT DSRTypes
 
     /// shortcut: print all codes (combines all PF_printXxxCodes flags, see above)
     static const size_t PF_printAllCodes;
-    //@}
+    ///@}
 
 
     /** @name checkByReferenceRelationships() modes
      *  These modes can be combined and passed to the checkByReferenceRelationships() method.
      */
-    //@{
+    ///@{
 
     /// update the position string using the node ID
     static const size_t CM_updatePositionString;
@@ -476,13 +476,13 @@ class DCMTK_DCMSR_EXPORT DSRTypes
 
     /// reset the reference target flag for all nodes
     static const size_t CM_resetReferenceTargetFlag;
-    //@}
+    ///@}
 
 
     /** @name checkByReferenceRelationships() bit masks
      *  These bit masks are used to "filter" valid flags passed to checkByReferenceRelationships().
      */
-    //@{
+    ///@{
 
     /// bit mask (filter) for valid print flags (see PF_xxx)
     static const size_t CB_maskPrintFlags;
@@ -490,7 +490,7 @@ class DCMTK_DCMSR_EXPORT DSRTypes
     /// bit mask (filter) for valid read flags (see RF_xxx)
     static const size_t CB_maskReadFlags;
 
-    //@}
+    ///@}
 
 
   // --- type definitions ---
@@ -657,8 +657,12 @@ class DCMTK_DCMSR_EXPORT DSRTypes
         PT_MultipleVolumeRendering,
         /// Variable Modality LUT Softcopy Presentation State (VML-SPS)
         PT_VariableModalityLUT,
+        /// Waveform Presentation State (WPS)
+        PT_Waveform,
+        /// Waveform Acquisition Presentation State (WAPS)
+        PT_WaveformAcquisition,
         /// internal type used to mark the last entry
-        PT_last = PT_VariableModalityLUT
+        PT_last = PT_WaveformAcquisition
     };
 
     /** SR graphic types.  Used for content item SCOORD.
index 3f7b5253812e39e1771b77a95d1a98a69bd2c7e5..a64c31323f45d067b98e3cddf80e33bcd6625f93 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -145,6 +145,10 @@ class DCMTK_DCMSR_EXPORT DSRWaveformReferenceValue
      *                       Value is increased automatically by 1 after a new entry has been added.
      *  @param  flags        flag used to customize the output (see DSRTypes::HF_xxx)
      *  @param  urlPrefix    optional URL prefix used for hyperlink to referenced composite object
+     ** @note Please note that using parameter 'urlPrefix' can lead to security issues, as an
+     *        attacker could misuse it to potentially inject dangerous content into the HTML/XHTML
+     *        output.  The value of this parameter is not checked.  This is also true for derived
+     *        classes.
      ** @return status, EC_Normal if successful, an error code otherwise
      */
     virtual OFCondition renderHTML(STD_NAMESPACE ostream &docStream,
index afd7a0c90de219a07dc7d92849ee5a49dc20261f..548089d0ba1527b17b8f54db2e79e27d204e149d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2003-2024, OFFIS e.V.
+ *  Copyright (C) 2003-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #define DSRXMLC_H
 
 #include "dcmtk/config/osconfig.h"   /* make sure OS specific configuration is included first */
-
 #include "dcmtk/dcmsr/dsdefine.h"
-
 #include "dcmtk/ofstd/oftypes.h"    /* for definition of OFBool */
+#include "dcmtk/ofstd/ofdiag.h"
 
 #ifdef WITH_LIBXML
 
 #define LIBXML_ATTR_FORMAT(fmt,args)
 #endif
 
+// MacOS 15.5 defines some Clang specific pragmas in libxml header files.
+// Suppress warnings caused by these pragmas when compiling with GCC.
+#include DCMTK_DIAGNOSTIC_PUSH
+#include DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC
 #include <libxml/parser.h>
+#include DCMTK_DIAGNOSTIC_POP
+
 #endif
 
 
index c1fc65c034421d951588e5a6172ed94b5ec53d8d..5a690c17ea815367ed37b2ac0f7b9b872799aa9e 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID100_QuantitativeDiagnosticImagingProcedure
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:09 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:43 by J. Riesmeier
  *
  */
 
@@ -18,7 +18,8 @@
 
 // general information on CID 100 (Quantitative Diagnostic Imaging Procedure)
 #define CONTEXT_GROUP_NUMBER  "100"
-#define CONTEXT_GROUP_VERSION "20230630"
+#define CONTEXT_GROUP_KEYWORD "QuantitativeDiagnosticImagingProcedure"
+#define CONTEXT_GROUP_VERSION "20250122"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.998"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
 
@@ -27,7 +28,7 @@ CID100_QuantitativeDiagnosticImagingProcedure::CodeList *CID100_QuantitativeDiag
 
 
 CID100_QuantitativeDiagnosticImagingProcedure::CID100_QuantitativeDiagnosticImagingProcedure(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID100_QuantitativeDiagnosticImagingProcedure::CID100_QuantitativeDiagnosticImag
 
 CID100_QuantitativeDiagnosticImagingProcedure::CID100_QuantitativeDiagnosticImagingProcedure(const EnumType selectedValue,
                                                                                              const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -167,7 +168,6 @@ CID100_QuantitativeDiagnosticImagingProcedure::CodeList &CID100_QuantitativeDiag
         Codes->insert(OFMake_pair(PETCT_METImagingOfWholeBody, DSRBasicCodedEntry("764704008", "SCT", "PET/CT MET imaging of whole body")));
         Codes->insert(OFMake_pair(CTPerfusionHeadWithContrastIV, DSRBasicCodedEntry("39142-5", "LN", "CT perfusion head with contrast IV")));
         Codes->insert(OFMake_pair(SPECTBrain, DSRBasicCodedEntry("39632-5", "LN", "SPECT brain")));
-        Codes->insert(OFMake_pair(NMHeadPerfusionBrainPET_CT_AV45, DSRBasicCodedEntry("RPID5427", "RADLEX", "NM head perfusion brain PET-CT AV-45")));
     }
     /* should never be NULL */
     return *Codes;
index af30769e40ccfa44ae289c3785f51bf30bee4abe..9fbd5f99ad62df1259d30b81e4ac019a755806d3 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID10013_CTAcquisitionType
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:25 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:57 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 10013 (CT Acquisition Type)
 #define CONTEXT_GROUP_NUMBER  "10013"
+#define CONTEXT_GROUP_KEYWORD "CTAcquisitionType"
 #define CONTEXT_GROUP_VERSION "20160314"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.545"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID10013_CTAcquisitionType::CodeList *CID10013_CTAcquisitionType::Codes = NULL;
 
 
 CID10013_CTAcquisitionType::CID10013_CTAcquisitionType(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID10013_CTAcquisitionType::CID10013_CTAcquisitionType(const DSRCodedEntryValue
 
 CID10013_CTAcquisitionType::CID10013_CTAcquisitionType(const EnumType selectedValue,
                                                        const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 87e2531d9215aaaf29024a8577c0b091755452e5..d098da6e709e28278307138fb388e1cbb1e75528 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID10033_CTReconstructionAlgorithm
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:26 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:58 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 10033 (CT Reconstruction Algorithm)
 #define CONTEXT_GROUP_NUMBER  "10033"
+#define CONTEXT_GROUP_KEYWORD "CTReconstructionAlgorithm"
 #define CONTEXT_GROUP_VERSION "20130207"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.958"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID10033_CTReconstructionAlgorithm::CodeList *CID10033_CTReconstructionAlgorithm
 
 
 CID10033_CTReconstructionAlgorithm::CID10033_CTReconstructionAlgorithm(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID10033_CTReconstructionAlgorithm::CID10033_CTReconstructionAlgorithm(const DSR
 
 CID10033_CTReconstructionAlgorithm::CID10033_CTReconstructionAlgorithm(const EnumType selectedValue,
                                                                        const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index e6e61071bfa02d7e837ba0d357b6bfe7844ebf41..6af4790e7a4a6c77cce631892e967684041c0b3d 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID11_AdministrationRoute
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:06 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:40 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 11 (Administration Route)
 #define CONTEXT_GROUP_NUMBER  "11"
+#define CONTEXT_GROUP_KEYWORD "AdministrationRoute"
 #define CONTEXT_GROUP_VERSION "20240611"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.9"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID11_AdministrationRoute::CodeList *CID11_AdministrationRoute::Codes = NULL;
 
 
 CID11_AdministrationRoute::CID11_AdministrationRoute(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID11_AdministrationRoute::CID11_AdministrationRoute(const DSRCodedEntryValue &s
 
 CID11_AdministrationRoute::CID11_AdministrationRoute(const EnumType selectedValue,
                                                      const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 96b3fa1599c4c4f251b49fb078a99a9779f5d180..4d0bf00142e9be0f726ffe892793e4df76ff23d9 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID218_QuantitativeImageFeature
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:10 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:44 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 218 (Quantitative Image Feature)
 #define CONTEXT_GROUP_NUMBER  "218"
+#define CONTEXT_GROUP_KEYWORD "QuantitativeImageFeature"
 #define CONTEXT_GROUP_VERSION "20200920"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1269"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID218_QuantitativeImageFeature::CodeList *CID218_QuantitativeImageFeature::Code
 
 
 CID218_QuantitativeImageFeature::CID218_QuantitativeImageFeature(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID218_QuantitativeImageFeature::CID218_QuantitativeImageFeature(const DSRCodedE
 
 CID218_QuantitativeImageFeature::CID218_QuantitativeImageFeature(const EnumType selectedValue,
                                                                  const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 6550718e091c76645bbd3fd956f7592a5f539450..a77fd9475163fc037570f4e78592b14efee38abc 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID244_Laterality
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:11 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:45 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 244 (Laterality)
 #define CONTEXT_GROUP_NUMBER  "244"
+#define CONTEXT_GROUP_KEYWORD "Laterality"
 #define CONTEXT_GROUP_VERSION "20030108"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.37"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID244_Laterality::CodeList *CID244_Laterality::Codes = NULL;
 
 
 CID244_Laterality::CID244_Laterality(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID244_Laterality::CID244_Laterality(const DSRCodedEntryValue &selectedValue)
 
 CID244_Laterality::CID244_Laterality(const EnumType selectedValue,
                                      const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 41640c58f87b5cfc0f0a349d529038bbbda3192e..b8ac53a96a1ee855c06ce1ef46fabf659d9d60d8 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID247_LateralityLeftRightOnly
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:12 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:45 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 247 (Laterality Left-Right Only)
 #define CONTEXT_GROUP_NUMBER  "247"
+#define CONTEXT_GROUP_KEYWORD "LateralityLeftRightOnly"
 #define CONTEXT_GROUP_VERSION "20190524"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1284"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID247_LateralityLeftRightOnly::CodeList *CID247_LateralityLeftRightOnly::Codes
 
 
 CID247_LateralityLeftRightOnly::CID247_LateralityLeftRightOnly(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID247_LateralityLeftRightOnly::CID247_LateralityLeftRightOnly(const DSRCodedEnt
 
 CID247_LateralityLeftRightOnly::CID247_LateralityLeftRightOnly(const EnumType selectedValue,
                                                                const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 6da715695f8308f61ed25edf84f611c21f2975a7..16f2ce5b49539816a5d1b803573b0e21e5a14332 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID29_AcquisitionModality
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:07 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:41 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 29 (Acquisition Modality)
 #define CONTEXT_GROUP_NUMBER  "29"
+#define CONTEXT_GROUP_KEYWORD "AcquisitionModality"
 #define CONTEXT_GROUP_VERSION "20231115"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.19"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID29_AcquisitionModality::CodeList *CID29_AcquisitionModality::Codes = NULL;
 
 
 CID29_AcquisitionModality::CID29_AcquisitionModality(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID29_AcquisitionModality::CID29_AcquisitionModality(const DSRCodedEntryValue &s
 
 CID29_AcquisitionModality::CID29_AcquisitionModality(const EnumType selectedValue,
                                                      const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -165,7 +166,7 @@ CID29_AcquisitionModality::CodeList &CID29_AcquisitionModality::getCodes()
         Codes->insert(OFMake_pair(IntravascularOpticalCoherenceTomography, DSRBasicCodedEntry("IVOCT", "DCM", "Intravascular Optical Coherence Tomography")));
         Codes->insert(OFMake_pair(IntravascularUltrasound, DSRBasicCodedEntry("IVUS", "DCM", "Intravascular Ultrasound")));
         Codes->insert(OFMake_pair(Keratometry, DSRBasicCodedEntry("KER", "DCM", "Keratometry")));
-        Codes->insert(OFMake_pair(LaserScan, DSRBasicCodedEntry("LS", "DCM", "Laser Scan")));
+        Codes->insert(OFMake_pair(LaserSurfaceScan, DSRBasicCodedEntry("LS", "DCM", "Laser surface scan")));
         Codes->insert(OFMake_pair(Lensometry, DSRBasicCodedEntry("LEN", "DCM", "Lensometry")));
         Codes->insert(OFMake_pair(MagneticResonance, DSRBasicCodedEntry("MR", "DCM", "Magnetic Resonance")));
         Codes->insert(OFMake_pair(Mammography, DSRBasicCodedEntry("MG", "DCM", "Mammography")));
index 88e913efde7ff3258a2bae44ebe75c37b81ef587..89cf9904a321a819cc2c7f4a9e84805bc288c3f7 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID4020_PETRadionuclide
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:13 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:46 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 4020 (PET Radionuclide)
 #define CONTEXT_GROUP_NUMBER  "4020"
+#define CONTEXT_GROUP_KEYWORD "PETRadionuclide"
 #define CONTEXT_GROUP_VERSION "20160119"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.304"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID4020_PETRadionuclide::CodeList *CID4020_PETRadionuclide::Codes = NULL;
 
 
 CID4020_PETRadionuclide::CID4020_PETRadionuclide(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID4020_PETRadionuclide::CID4020_PETRadionuclide(const DSRCodedEntryValue &selec
 
 CID4020_PETRadionuclide::CID4020_PETRadionuclide(const EnumType selectedValue,
                                                  const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index fee7a9758fd6e5f53e72c6f23a175dadd02bc342..47ab072d9e8588e713857998541663821742e47e 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID4021_PETRadiopharmaceutical
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:14 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:47 by J. Riesmeier
  *
  */
 
@@ -18,7 +18,8 @@
 
 // general information on CID 4021 (PET Radiopharmaceutical)
 #define CONTEXT_GROUP_NUMBER  "4021"
-#define CONTEXT_GROUP_VERSION "20221201"
+#define CONTEXT_GROUP_KEYWORD "PETRadiopharmaceutical"
+#define CONTEXT_GROUP_VERSION "20251111"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.305"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
 
@@ -27,7 +28,7 @@ CID4021_PETRadiopharmaceutical::CodeList *CID4021_PETRadiopharmaceutical::Codes
 
 
 CID4021_PETRadiopharmaceutical::CID4021_PETRadiopharmaceutical(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID4021_PETRadiopharmaceutical::CID4021_PETRadiopharmaceutical(const DSRCodedEnt
 
 CID4021_PETRadiopharmaceutical::CID4021_PETRadiopharmaceutical(const EnumType selectedValue,
                                                                const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -151,6 +152,8 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         /* and initialize it by adding the coded entries */
         Codes->insert(OFMake_pair(_28H1_89Zr, DSRBasicCodedEntry("126752", "DCM", "28H1 ^89^Zr")));
         Codes->insert(OFMake_pair(_2FA_F18, DSRBasicCodedEntry("126713", "DCM", "2FA F^18^")));
+        Codes->insert(OFMake_pair(_2Thymidine_C11, DSRBasicCodedEntry("C90936", "NCIt", "2-Thymidine C^11^")));
+        Codes->insert(OFMake_pair(_3NMethylspiperone_C11, DSRBasicCodedEntry("771875003", "SCT", "3-N-Methylspiperone C^11^")));
         Codes->insert(OFMake_pair(_7D12_89Zr, DSRBasicCodedEntry("126751", "DCM", "7D12 ^89^Zr")));
         Codes->insert(OFMake_pair(_7E11_89Zr, DSRBasicCodedEntry("126750", "DCM", "7E11 ^89^Zr")));
         Codes->insert(OFMake_pair(Acetate_C11, DSRBasicCodedEntry("129513004", "SCT", "Acetate C^11^")));
@@ -177,14 +180,15 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(CLR1404_I131, DSRBasicCodedEntry("126716", "DCM", "CLR1404 I^131^")));
         Codes->insert(OFMake_pair(CMAbU36_89Zr, DSRBasicCodedEntry("126746", "DCM", "cMAb U36 ^89^Zr")));
         Codes->insert(OFMake_pair(CU36_89Zr, DSRBasicCodedEntry("126515", "DCM", "cU36 ^89^Zr")));
+        Codes->insert(OFMake_pair(DASB_C11, DSRBasicCodedEntry("C412822", "MSH", "DASB C^11^")));
         Codes->insert(OFMake_pair(DCFBC_F18, DSRBasicCodedEntry("C96234", "NCIt", "DCFBC F^18^")));
-        Codes->insert(OFMake_pair(Piflufolastat_F18, DSRBasicCodedEntry("C116352", "NCIt", "Piflufolastat F^18^")));
         Codes->insert(OFMake_pair(DfFK2_89Zr, DSRBasicCodedEntry("126762", "DCM", "Df-[FK](2) ^89^Zr")));
         Codes->insert(OFMake_pair(DfFK23PEG4_89Zr, DSRBasicCodedEntry("126763", "DCM", "Df-[FK](2)-3PEG(4) ^89^Zr")));
         Codes->insert(OFMake_pair(DfCD45_89Zr, DSRBasicCodedEntry("126520", "DCM", "Df-CD45 ^89^Zr")));
         Codes->insert(OFMake_pair(DfFK_89Zr, DSRBasicCodedEntry("126760", "DCM", "Df-FK ^89^Zr")));
         Codes->insert(OFMake_pair(DfFKPEG3_89Zr, DSRBasicCodedEntry("126761", "DCM", "Df-FK-PEG(3) ^89^Zr")));
         Codes->insert(OFMake_pair(DN30_89Zr, DSRBasicCodedEntry("126747", "DCM", "DN30 ^89^Zr")));
+        Codes->insert(OFMake_pair(Dotatate_Ga68, DSRBasicCodedEntry("724025002", "SCT", "Dotatate Ga^68^")));
         Codes->insert(OFMake_pair(DPA713_11C, DSRBasicCodedEntry("126765", "DCM", "DPA-713 ^11^C")));
         Codes->insert(OFMake_pair(DPA714_18F, DSRBasicCodedEntry("126766", "DCM", "DPA-714 ^18^F")));
         Codes->insert(OFMake_pair(E4G10_89Zr, DSRBasicCodedEntry("126519", "DCM", "E4G10 ^89^Zr")));
@@ -203,6 +207,7 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(Flumazenil_C11, DSRBasicCodedEntry("423543007", "SCT", "Flumazenil C^11^")));
         Codes->insert(OFMake_pair(Flumazenil_F18, DSRBasicCodedEntry("422975006", "SCT", "Flumazenil F^18^")));
         Codes->insert(OFMake_pair(Fluorethyltyrosin_F18, DSRBasicCodedEntry("424708001", "SCT", "Fluorethyltyrosin F^18^")));
+        Codes->insert(OFMake_pair(FluoroazomycinArabinoside_F18, DSRBasicCodedEntry("C62520", "NCIt", "Fluoroazomycin arabinoside F^18^")));
         Codes->insert(OFMake_pair(Fluorobenzothiazole_F18, DSRBasicCodedEntry("423546004", "SCT", "Fluorobenzothiazole F^18^")));
         Codes->insert(OFMake_pair(Fluorocholine_F18, DSRBasicCodedEntry("456992002", "SCT", "Fluorocholine F^18^")));
         Codes->insert(OFMake_pair(Fluorodeoxyglucose_F18, DSRBasicCodedEntry("35321007", "SCT", "Fluorodeoxyglucose F^18^")));
@@ -212,6 +217,7 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(Fluoromethane_F18, DSRBasicCodedEntry("422763008", "SCT", "Fluoromethane F^18^")));
         Codes->insert(OFMake_pair(Fluoromisonidazole_F18, DSRBasicCodedEntry("422598008", "SCT", "Fluoromisonidazole F^18^")));
         Codes->insert(OFMake_pair(FluoropropylDihydrotetrabenazine_F18, DSRBasicCodedEntry("C2934038", "UMLS", "Fluoropropyl-dihydrotetrabenazine F^18^")));
+        Codes->insert(OFMake_pair(Fluorothymidine_F18, DSRBasicCodedEntry("764937002", "SCT", "Fluorothymidine F^18^")));
         Codes->insert(OFMake_pair(Fluorotriopride_F18, DSRBasicCodedEntry("126707", "DCM", "Fluorotriopride F^18^")));
         Codes->insert(OFMake_pair(Fluorouracil_F18, DSRBasicCodedEntry("425236000", "SCT", "Fluorouracil F^18^")));
         Codes->insert(OFMake_pair(Flurpiridaz_F18, DSRBasicCodedEntry("126718", "DCM", "Flurpiridaz F^18^")));
@@ -220,6 +226,7 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(GA201_89Zr, DSRBasicCodedEntry("126731", "DCM", "GA201 ^89^Zr")));
         Codes->insert(OFMake_pair(Germanium_Ge68, DSRBasicCodedEntry("53315004", "SCT", "Germanium Ge^68^")));
         Codes->insert(OFMake_pair(GlembatumumabVedotin_89Zr, DSRBasicCodedEntry("126724", "DCM", "Glembatumumab vedotin ^89^Zr")));
+        Codes->insert(OFMake_pair(Glucose_C11, DSRBasicCodedEntry("126521", "DCM", "Glucose C^11^")));
         Codes->insert(OFMake_pair(Glutamate_N13, DSRBasicCodedEntry("129509006", "SCT", "Glutamate N^13^")));
         Codes->insert(OFMake_pair(Glutamine_C11, DSRBasicCodedEntry("126709", "DCM", "Glutamine C^11^")));
         Codes->insert(OFMake_pair(Glutamine_C14, DSRBasicCodedEntry("126710", "DCM", "Glutamine C^14^")));
@@ -244,6 +251,9 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(Palmitate_C11, DSRBasicCodedEntry("129514005", "SCT", "Palmitate C^11^")));
         Codes->insert(OFMake_pair(Panitumumab_89Zr, DSRBasicCodedEntry("126736", "DCM", "Panitumumab ^89^Zr")));
         Codes->insert(OFMake_pair(Pegdinetanib_89Zr, DSRBasicCodedEntry("126728", "DCM", "Pegdinetanib ^89^Zr")));
+        Codes->insert(OFMake_pair(Pembrolizumab_89Zr, DSRBasicCodedEntry("C148167", "NCIt", "Pembrolizumab ^89^Zr")));
+        Codes->insert(OFMake_pair(PI2620_F18, DSRBasicCodedEntry("C5433257", "UMLS", "PI-2620 F^18^")));
+        Codes->insert(OFMake_pair(Piflufolastat_F18, DSRBasicCodedEntry("C116352", "NCIt", "Piflufolastat F^18^")));
         Codes->insert(OFMake_pair(PinatuzumabVedotin_89Zr, DSRBasicCodedEntry("126725", "DCM", "Pinatuzumab vedotin ^89^Zr")));
         Codes->insert(OFMake_pair(PittsburghCompoundB_C11, DSRBasicCodedEntry("126500", "DCM", "Pittsburgh compound B C^11^")));
         Codes->insert(OFMake_pair(PK11195_11C, DSRBasicCodedEntry("C1609883", "UMLS", "PK11195 ^11^C")));
@@ -272,10 +282,8 @@ CID4021_PETRadiopharmaceutical::CodeList &CID4021_PETRadiopharmaceutical::getCod
         Codes->insert(OFMake_pair(T807_F18, DSRBasicCodedEntry("126502", "DCM", "T807 F^18^")));
         Codes->insert(OFMake_pair(THK5317_F18, DSRBasicCodedEntry("C4550127", "UMLS", "THK5317 F^18^")));
         Codes->insert(OFMake_pair(THK5351_F18, DSRBasicCodedEntry("C4279748", "UMLS", "THK5351 F^18^")));
-        Codes->insert(OFMake_pair(Thymidine_F18, DSRBasicCodedEntry("129502002", "SCT", "Thymidine F^18^")));
         Codes->insert(OFMake_pair(Trastuzumab_89Zr, DSRBasicCodedEntry("126512", "DCM", "Trastuzumab ^89^Zr")));
         Codes->insert(OFMake_pair(TRC105_89Zr, DSRBasicCodedEntry("126749", "DCM", "TRC105 ^89^Zr")));
-        Codes->insert(OFMake_pair(Dotatate_Ga68, DSRBasicCodedEntry("724025002", "SCT", "Dotatate Ga^68^")));
         Codes->insert(OFMake_pair(Ublituximab_89Zr, DSRBasicCodedEntry("126739", "DCM", "Ublituximab ^89^Zr")));
         Codes->insert(OFMake_pair(UCBJ_C11, DSRBasicCodedEntry("C4506788", "UMLS", "UCB-J C^11^")));
         Codes->insert(OFMake_pair(XmAb5574_89Zr, DSRBasicCodedEntry("126734", "DCM", "XmAb5574 ^89^Zr")));
index ec254824936e81cfe9f6ef0e50c58877fbbd8c99..4cdedd117a5391018c592875a3e51a9502d010bc 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID4031_CommonAnatomicRegion
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:15 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:48 by J. Riesmeier
  *
  */
 
@@ -18,7 +18,8 @@
 
 // general information on CID 4031 (Common Anatomic Region)
 #define CONTEXT_GROUP_NUMBER  "4031"
-#define CONTEXT_GROUP_VERSION "20221224"
+#define CONTEXT_GROUP_KEYWORD "CommonAnatomicRegion"
+#define CONTEXT_GROUP_VERSION "20250709"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.308"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
 
@@ -27,7 +28,7 @@ CID4031_CommonAnatomicRegion::CodeList *CID4031_CommonAnatomicRegion::Codes = NU
 
 
 CID4031_CommonAnatomicRegion::CID4031_CommonAnatomicRegion(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID4031_CommonAnatomicRegion::CID4031_CommonAnatomicRegion(const DSRCodedEntryVa
 
 CID4031_CommonAnatomicRegion::CID4031_CommonAnatomicRegion(const EnumType selectedValue,
                                                            const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -163,11 +164,12 @@ CID4031_CommonAnatomicRegion::CodeList &CID4031_CommonAnatomicRegion::getCodes()
         Codes->insert(OFMake_pair(Breast, DSRBasicCodedEntry("76752008", "SCT", "Breast")));
         Codes->insert(OFMake_pair(Bronchus, DSRBasicCodedEntry("955009", "SCT", "Bronchus")));
         Codes->insert(OFMake_pair(Calcaneus, DSRBasicCodedEntry("80144004", "SCT", "Calcaneus")));
+        Codes->insert(OFMake_pair(CardiovascularSystem, DSRBasicCodedEntry("113257007", "SCT", "Cardiovascular system")));
         Codes->insert(OFMake_pair(CervicalSpine, DSRBasicCodedEntry("122494005", "SCT", "Cervical spine")));
         Codes->insert(OFMake_pair(CervicoThoracicSpine, DSRBasicCodedEntry("1217257000", "SCT", "Cervico-thoracic spine")));
         Codes->insert(OFMake_pair(Chest, DSRBasicCodedEntry("816094009", "SCT", "Chest")));
-        Codes->insert(OFMake_pair(ChestAndAbdomen, DSRBasicCodedEntry("416550000", "SCT", "Chest and Abdomen")));
         Codes->insert(OFMake_pair(ChestAbdomenAndPelvis, DSRBasicCodedEntry("416775004", "SCT", "Chest, Abdomen and Pelvis")));
+        Codes->insert(OFMake_pair(ChestAndAbdomen, DSRBasicCodedEntry("416550000", "SCT", "Chest and Abdomen")));
         Codes->insert(OFMake_pair(Clavicle, DSRBasicCodedEntry("51299004", "SCT", "Clavicle")));
         Codes->insert(OFMake_pair(Coccyx, DSRBasicCodedEntry("64688005", "SCT", "Coccyx")));
         Codes->insert(OFMake_pair(Colon, DSRBasicCodedEntry("71854001", "SCT", "Colon")));
@@ -205,6 +207,7 @@ CID4031_CommonAnatomicRegion::CodeList &CID4031_CommonAnatomicRegion::getCodes()
         Codes->insert(OFMake_pair(LiverAndBiliaryStructure, DSRBasicCodedEntry("303270005", "SCT", "Liver and biliary structure")));
         Codes->insert(OFMake_pair(LowerLeg, DSRBasicCodedEntry("30021000", "SCT", "Lower leg")));
         Codes->insert(OFMake_pair(LowerLimb, DSRBasicCodedEntry("61685007", "SCT", "Lower limb")));
+        Codes->insert(OFMake_pair(LowerTrunk, DSRBasicCodedEntry("63337009", "SCT", "Lower trunk")));
         Codes->insert(OFMake_pair(LumbarSpine, DSRBasicCodedEntry("122496007", "SCT", "Lumbar spine")));
         Codes->insert(OFMake_pair(LumboSacralSpine, DSRBasicCodedEntry("1217253001", "SCT", "Lumbo-sacral spine")));
         Codes->insert(OFMake_pair(Mandible, DSRBasicCodedEntry("91609006", "SCT", "Mandible")));
@@ -215,9 +218,9 @@ CID4031_CommonAnatomicRegion::CodeList &CID4031_CommonAnatomicRegion::getCodes()
         Codes->insert(OFMake_pair(MuscleOfUpperLimb, DSRBasicCodedEntry("30608006", "SCT", "Muscle of upper limb")));
         Codes->insert(OFMake_pair(NasalBone, DSRBasicCodedEntry("74386004", "SCT", "Nasal bone")));
         Codes->insert(OFMake_pair(Neck, DSRBasicCodedEntry("45048000", "SCT", "Neck")));
-        Codes->insert(OFMake_pair(NeckAndChest, DSRBasicCodedEntry("417437006", "SCT", "Neck and Chest")));
-        Codes->insert(OFMake_pair(NeckChestAndAbdomen, DSRBasicCodedEntry("416152001", "SCT", "Neck, Chest and Abdomen")));
         Codes->insert(OFMake_pair(NeckChestAbdomenAndPelvis, DSRBasicCodedEntry("416319003", "SCT", "Neck, Chest, Abdomen and Pelvis")));
+        Codes->insert(OFMake_pair(NeckChestAndAbdomen, DSRBasicCodedEntry("416152001", "SCT", "Neck, Chest and Abdomen")));
+        Codes->insert(OFMake_pair(NeckAndChest, DSRBasicCodedEntry("417437006", "SCT", "Neck and Chest")));
         Codes->insert(OFMake_pair(OpticCanal, DSRBasicCodedEntry("55024004", "SCT", "Optic canal")));
         Codes->insert(OFMake_pair(OrbitalStructure, DSRBasicCodedEntry("363654007", "SCT", "Orbital structure")));
         Codes->insert(OFMake_pair(Pancreas, DSRBasicCodedEntry("15776009", "SCT", "Pancreas")));
@@ -242,6 +245,7 @@ CID4031_CommonAnatomicRegion::CodeList &CID4031_CommonAnatomicRegion::getCodes()
         Codes->insert(OFMake_pair(Skull, DSRBasicCodedEntry("89546000", "SCT", "Skull")));
         Codes->insert(OFMake_pair(SmallIntestine, DSRBasicCodedEntry("30315005", "SCT", "Small intestine")));
         Codes->insert(OFMake_pair(Spine, DSRBasicCodedEntry("421060004", "SCT", "Spine")));
+        Codes->insert(OFMake_pair(SpineAndPerOrCord, DSRBasicCodedEntry("737561001", "SCT", "Spine and/or cord")));
         Codes->insert(OFMake_pair(SternoclavicularJoint, DSRBasicCodedEntry("7844006", "SCT", "Sternoclavicular joint")));
         Codes->insert(OFMake_pair(Sternum, DSRBasicCodedEntry("56873002", "SCT", "Sternum")));
         Codes->insert(OFMake_pair(Stomach, DSRBasicCodedEntry("69695003", "SCT", "Stomach")));
@@ -254,8 +258,10 @@ CID4031_CommonAnatomicRegion::CodeList &CID4031_CommonAnatomicRegion::getCodes()
         Codes->insert(OFMake_pair(Thumb, DSRBasicCodedEntry("76505004", "SCT", "Thumb")));
         Codes->insert(OFMake_pair(Toe, DSRBasicCodedEntry("29707007", "SCT", "Toe")));
         Codes->insert(OFMake_pair(Trachea, DSRBasicCodedEntry("44567001", "SCT", "Trachea")));
+        Codes->insert(OFMake_pair(Trunk, DSRBasicCodedEntry("22943007", "SCT", "Trunk")));
         Codes->insert(OFMake_pair(UpperArm, DSRBasicCodedEntry("40983000", "SCT", "Upper arm")));
         Codes->insert(OFMake_pair(UpperLimb, DSRBasicCodedEntry("53120007", "SCT", "Upper limb")));
+        Codes->insert(OFMake_pair(UpperTrunk, DSRBasicCodedEntry("67734004", "SCT", "Upper trunk")));
         Codes->insert(OFMake_pair(UpperUrinaryTract, DSRBasicCodedEntry("431491007", "SCT", "Upper urinary tract")));
         Codes->insert(OFMake_pair(Ureter, DSRBasicCodedEntry("87953007", "SCT", "Ureter")));
         Codes->insert(OFMake_pair(Urethra, DSRBasicCodedEntry("13648007", "SCT", "Urethra")));
index 73e7fd06d13ada78a414b12cc0a3e74508c3a8af..a9970ad0881decc473af8d9b5afbbb179afaa104 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID42_NumericValueQualifier
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:08 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:42 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 42 (Numeric Value Qualifier)
 #define CONTEXT_GROUP_NUMBER  "42"
+#define CONTEXT_GROUP_KEYWORD "NumericValueQualifier"
 #define CONTEXT_GROUP_VERSION "20020114"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.22"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID42_NumericValueQualifier::CodeList *CID42_NumericValueQualifier::Codes = NULL
 
 
 CID42_NumericValueQualifier::CID42_NumericValueQualifier(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID42_NumericValueQualifier::CID42_NumericValueQualifier(const DSRCodedEntryValu
 
 CID42_NumericValueQualifier::CID42_NumericValueQualifier(const EnumType selectedValue,
                                                          const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 45974a0292e1871e2b3c84ac896cd43d61263b47..f965fb370d6b4df8481438bf778f9b8a745ed034 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID5000_Language
@@ -17,6 +17,7 @@
 
 // general information on CID 5000 (Language)
 #define CONTEXT_GROUP_NUMBER  "5000"
+#define CONTEXT_GROUP_KEYWORD "Language"
 #define CONTEXT_GROUP_VERSION ""      /* unknown */
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.328"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible? */
@@ -26,7 +27,7 @@ CID5000_Language::CodeList *CID5000_Language::Codes = NULL;
 
 
 CID5000_Language::CID5000_Language(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -34,7 +35,7 @@ CID5000_Language::CID5000_Language(const DSRCodedEntryValue &selectedValue)
 
 CID5000_Language::CID5000_Language(const EnumType selectedValue,
                                   const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 28d9d945e7ef57c4c7ab17ac4c487c1d1e94ad21..e70ec8f809d0aa753a91080e3dc268a7a7e05191 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID5001_Country
@@ -17,6 +17,7 @@
 
 // general information on CID 5001 (Country)
 #define CONTEXT_GROUP_NUMBER  "5001"
+#define CONTEXT_GROUP_KEYWORD "Country"
 #define CONTEXT_GROUP_VERSION ""      /* unknown */
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.329"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible? */
@@ -26,7 +27,7 @@ CID5001_Country::CodeList *CID5001_Country::Codes = NULL;
 
 
 CID5001_Country::CID5001_Country(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -34,7 +35,7 @@ CID5001_Country::CID5001_Country(const DSRCodedEntryValue &selectedValue)
 
 CID5001_Country::CID5001_Country(const EnumType selectedValue,
                                  const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 9a58e1e7e26cdd63272e41c5be7a2032f48ff0a3..1bfaa7466b74fe3dffecef00d2ff9b703f7e34ee 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID6147_ResponseCriteria
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:16 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:49 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 6147 (Response Criteria)
 #define CONTEXT_GROUP_NUMBER  "6147"
+#define CONTEXT_GROUP_KEYWORD "ResponseCriteria"
 #define CONTEXT_GROUP_VERSION "20141110"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1004"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID6147_ResponseCriteria::CodeList *CID6147_ResponseCriteria::Codes = NULL;
 
 
 CID6147_ResponseCriteria::CID6147_ResponseCriteria(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID6147_ResponseCriteria::CID6147_ResponseCriteria(const DSRCodedEntryValue &sel
 
 CID6147_ResponseCriteria::CID6147_ResponseCriteria(const EnumType selectedValue,
                                                    const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index d70b58a310ffa0b5a95accb7372d9cabde6dd608..97e492ca42ce21150ce49b9792845d59a49d86da 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7021_MeasurementReportDocumentTitle
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:17 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:50 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7021 (Measurement Report Document Title)
 #define CONTEXT_GROUP_NUMBER  "7021"
+#define CONTEXT_GROUP_KEYWORD "MeasurementReportDocumentTitle"
 #define CONTEXT_GROUP_VERSION "20141110"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.997"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7021_MeasurementReportDocumentTitle::CodeList *CID7021_MeasurementReportDocum
 
 
 CID7021_MeasurementReportDocumentTitle::CID7021_MeasurementReportDocumentTitle(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7021_MeasurementReportDocumentTitle::CID7021_MeasurementReportDocumentTitle(c
 
 CID7021_MeasurementReportDocumentTitle::CID7021_MeasurementReportDocumentTitle(const EnumType selectedValue,
                                                                                const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 200328b3db2afb9b1993ac68d96acd1636a69996..fed9f931e2a1e7d7bc5fb3de8edd8f515609cb70 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7181_AbstractMultiDimensionalImageModelComponentUnit
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:18 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:51 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7181 (Abstract Multi-dimensional Image Model Component Unit)
 #define CONTEXT_GROUP_NUMBER  "7181"
+#define CONTEXT_GROUP_KEYWORD "AbstractMultiDimensionalImageModelComponentUnit"
 #define CONTEXT_GROUP_VERSION "20180605"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.918"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7181_AbstractMultiDimensionalImageModelComponentUnit::CodeList *CID7181_Abstr
 
 
 CID7181_AbstractMultiDimensionalImageModelComponentUnit::CID7181_AbstractMultiDimensionalImageModelComponentUnit(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7181_AbstractMultiDimensionalImageModelComponentUnit::CID7181_AbstractMultiDi
 
 CID7181_AbstractMultiDimensionalImageModelComponentUnit::CID7181_AbstractMultiDimensionalImageModelComponentUnit(const EnumType selectedValue,
                                                                                                                  const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index fc05b84e6caf7a52a5fe5bea49231c422f08cb8a..c411fe54f0342ba7a55d2cadbcb852cb34f34ccc 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7445_DeviceParticipatingRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:19 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:52 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7445 (Device Participating Role)
 #define CONTEXT_GROUP_NUMBER  "7445"
+#define CONTEXT_GROUP_KEYWORD "DeviceParticipatingRole"
 #define CONTEXT_GROUP_VERSION "20120406"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1042"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7445_DeviceParticipatingRole::CodeList *CID7445_DeviceParticipatingRole::Code
 
 
 CID7445_DeviceParticipatingRole::CID7445_DeviceParticipatingRole(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7445_DeviceParticipatingRole::CID7445_DeviceParticipatingRole(const DSRCodedE
 
 CID7445_DeviceParticipatingRole::CID7445_DeviceParticipatingRole(const EnumType selectedValue,
                                                                  const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 8bdcc10e113174bd40bba0c13ab5eccb9c531e41..360860992944ab644081f43481793ed0464fb444 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7452_OrganizationalRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:20 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:52 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7452 (Organizational Role)
 #define CONTEXT_GROUP_NUMBER  "7452"
+#define CONTEXT_GROUP_KEYWORD "OrganizationalRole"
 #define CONTEXT_GROUP_VERSION "20170626"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.516"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7452_OrganizationalRole::CodeList *CID7452_OrganizationalRole::Codes = NULL;
 
 
 CID7452_OrganizationalRole::CID7452_OrganizationalRole(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7452_OrganizationalRole::CID7452_OrganizationalRole(const DSRCodedEntryValue
 
 CID7452_OrganizationalRole::CID7452_OrganizationalRole(const EnumType selectedValue,
                                                        const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index ce6a674ea60339896b1dc129e4138fabebfabf2c..ce89897a6bbedf6f45075fde6f6aff2515cacec0 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7453_PerformingRole
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:21 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:53 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7453 (Performing Role)
 #define CONTEXT_GROUP_NUMBER  "7453"
+#define CONTEXT_GROUP_KEYWORD "PerformingRole"
 #define CONTEXT_GROUP_VERSION "20180326"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.517"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7453_PerformingRole::CodeList *CID7453_PerformingRole::Codes = NULL;
 
 
 CID7453_PerformingRole::CID7453_PerformingRole(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7453_PerformingRole::CID7453_PerformingRole(const DSRCodedEntryValue &selecte
 
 CID7453_PerformingRole::CID7453_PerformingRole(const EnumType selectedValue,
                                                const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index c91f87803b2a8f9d7199da7a2263862856daa29d..7a56d812428e1c337ee82a907838a3ea5541b777 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7464_GeneralRegionOfInterestMeasurementModifier
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:22 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:54 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7464 (General Region of Interest Measurement Modifier)
 #define CONTEXT_GROUP_NUMBER  "7464"
+#define CONTEXT_GROUP_KEYWORD "GeneralRegionOfInterestMeasurementModifier"
 #define CONTEXT_GROUP_VERSION "20121101"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.951"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7464_GeneralRegionOfInterestMeasurementModifier::CodeList *CID7464_GeneralReg
 
 
 CID7464_GeneralRegionOfInterestMeasurementModifier::CID7464_GeneralRegionOfInterestMeasurementModifier(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7464_GeneralRegionOfInterestMeasurementModifier::CID7464_GeneralRegionOfInter
 
 CID7464_GeneralRegionOfInterestMeasurementModifier::CID7464_GeneralRegionOfInterestMeasurementModifier(const EnumType selectedValue,
                                                                                                        const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 81466ba599c4e18134de308a060b29cf9705d6ed..1a53f0c8cdd6307b657fcc8bb51078991620b388 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7469_GenericIntensityAndSizeMeasurement
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:23 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:55 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7469 (Generic Intensity and Size Measurement)
 #define CONTEXT_GROUP_NUMBER  "7469"
+#define CONTEXT_GROUP_KEYWORD "GenericIntensityAndSizeMeasurement"
 #define CONTEXT_GROUP_VERSION "20240913"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1003"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7469_GenericIntensityAndSizeMeasurement::CodeList *CID7469_GenericIntensityAn
 
 
 CID7469_GenericIntensityAndSizeMeasurement::CID7469_GenericIntensityAndSizeMeasurement(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7469_GenericIntensityAndSizeMeasurement::CID7469_GenericIntensityAndSizeMeasu
 
 CID7469_GenericIntensityAndSizeMeasurement::CID7469_GenericIntensityAndSizeMeasurement(const EnumType selectedValue,
                                                                                        const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 22c79cc1fb806cf65dad4316fd4af54ed2be6eed..64b3bf2ce560bb08f0690a2cf422306fa1352455 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *
- *  Copyright (C) 2015-2024, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  Source file for class CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement
  *
- *  Generated automatically from DICOM PS 3.16-2024d
- *  File created on 2024-10-08 10:25:24 by J. Riesmeier
+ *  Generated automatically from DICOM PS 3.16-2025e
+ *  File created on 2025-11-21 12:16:56 by J. Riesmeier
  *
  */
 
@@ -18,6 +18,7 @@
 
 // general information on CID 7551 (Generic Purpose of Reference to Images and Coordinates in Measurement)
 #define CONTEXT_GROUP_NUMBER  "7551"
+#define CONTEXT_GROUP_KEYWORD "GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement"
 #define CONTEXT_GROUP_VERSION "20200920"
 #define CONTEXT_GROUP_UID     "1.2.840.10008.6.1.1343"
 #define CONTEXT_GROUP_TYPE    OFTrue  /* extensible */
@@ -27,7 +28,7 @@ CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement::CodeList *
 
 
 CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement::CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement(const DSRCodedEntryValue &selectedValue)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, selectedValue)
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
@@ -35,7 +36,7 @@ CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement::CID7551_Ge
 
 CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement::CID7551_GenericPurposeOfReferenceToImagesAndCoordinatesInMeasurement(const EnumType selectedValue,
                                                                                                                                            const OFBool enhancedEncodingMode)
-  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
+  : DSRContextGroup(CONTEXT_GROUP_NUMBER, "DCMR", CONTEXT_GROUP_KEYWORD, CONTEXT_GROUP_VERSION, CONTEXT_GROUP_UID, getCodedEntry(selectedValue, enhancedEncodingMode))
 {
     setExtensible(CONTEXT_GROUP_TYPE);
 }
index 33344c7241b304e402b4c09630c94141786770fb..b628937107216e09bf825d6a68fcc33f42c22e30 100644 (file)
@@ -1355,8 +1355,9 @@ dsrdoc.o: dsrdoc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -2061,6 +2062,7 @@ dsrimgvl.o: dsrimgvl.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dipixel.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimomod.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/diluptab.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrobow.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dibaslut.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/dimoopx.h \
  ../../dcmimgle/include/dcmtk/dcmimgle/didispfn.h \
@@ -5283,7 +5285,8 @@ dsrxmlc.o: dsrxmlc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/ofcast.h \
  ../../ofstd/include/dcmtk/ofstd/ofexport.h \
  ../../ofstd/include/dcmtk/ofstd/oftypes.h \
- ../../ofstd/include/dcmtk/ofstd/ofstdinc.h
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h
 dsrxmld.o: dsrxmld.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrxmld.h ../include/dcmtk/dcmsr/dsrtypes.h \
  ../include/dcmtk/dcmsr/dsdefine.h \
index f9585b1dd41318c876820a774d3ecc164d7a6a83..f3ab5db23457cf1baf7c773407def2ceb744d258 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2016, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 
 DSRContextGroup::DSRContextGroup(const OFString &contextIdentifier,
                                  const OFString &mappingResource,
+                                 const OFString &contextGroupKeyword,
                                  const OFString &contextGroupVersion,
                                  const OFString &contextGroupUID,
                                  const DSRCodedEntryValue &selectedValue)
   : Identifier(contextIdentifier),
     MappingResource(mappingResource),
+    Keyword(contextGroupKeyword),
     Version(contextGroupVersion),
     UID(contextGroupUID),
     SelectedValue(selectedValue),
@@ -149,6 +151,7 @@ void DSRContextGroup::printHeader(STD_NAMESPACE ostream &stream) const
     /* output some general information on the context group */
     stream << "CID " << getIdentifier() << OFendl;
     stream << "  Resource : " << getMappingResource() << OFendl;
+    stream << "  Keyword  : " << getKeyword() << OFendl;
     stream << "  Version  : " << getVersion() << OFendl;
     stream << "  UID      : " << getUID() << OFendl;
     stream << "  Type     : " << (isExtensible() ? "extensible" : "non-extensible") << OFendl;
index 30d747696114b23de2cfed8e668a250419185512..6dd15dde9d35bc9d9c9c4117387b25ffb9ac7bb8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2022, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -82,6 +82,7 @@ DSRDocument::DSRDocument(const E_DocumentType documentType)
     IssuerOfPatientID(DCM_IssuerOfPatientID),
     PatientBirthDate(DCM_PatientBirthDate),
     PatientSex(DCM_PatientSex),
+    PatientAge(DCM_PatientAge),
     PatientSize(DCM_PatientSize),
     PatientWeight(DCM_PatientWeight),
     Manufacturer(DCM_Manufacturer),
@@ -156,6 +157,7 @@ void DSRDocument::clear()
     IssuerOfPatientID.clear();
     PatientBirthDate.clear();
     PatientSex.clear();
+    PatientAge.clear();
     PatientSize.clear();
     PatientWeight.clear();
     Manufacturer.clear();
@@ -592,6 +594,8 @@ OFCondition DSRDocument::read(DcmItem &dataset,
             VerificationFlagEnum = enumeratedValueToVerificationFlag(getStringValueFromElement(VerificationFlag, tmpString));
             if (VerificationFlagEnum == VF_invalid)
                 printUnknownValueWarningMessage("VerificationFlag", tmpString.c_str());
+            else if ((VerificationFlagEnum == VF_Unverified) && !VerifyingObserver.isEmpty())
+                DCMSR_WARN("Verifying Observer(s) should not be present when Verification Flag is 'UNVERIFIED'");
             else if (VerificationFlagEnum == VF_Verified)
                 checkElementValue(VerifyingObserver, "1-n", "1", obsSearchCond, "SRDocumentGeneralModule");
         }
@@ -635,6 +639,7 @@ OFCondition DSRDocument::readStudyData(DcmItem &dataset,
     getAndCheckElementFromDataset(dataset, AccessionNumber, "1", "2", "GeneralStudyModule");
     getAndCheckElementFromDataset(dataset, StudyDescription, "1", "3", "GeneralStudyModule");
     // --- Patient Study Module ---
+    getAndCheckElementFromDataset(dataset, PatientAge, "1", "3", "PatientStudyModule");
     getAndCheckElementFromDataset(dataset, PatientSize, "1", "3", "PatientStudyModule");
     getAndCheckElementFromDataset(dataset, PatientWeight, "1", "3", "PatientStudyModule");
     /* also read data from Patient Module */
@@ -695,6 +700,7 @@ OFCondition DSRDocument::write(DcmItem &dataset,
         addElementToDataset(result, dataset, new DcmCodeString(PatientSex), "1", "2", "PatientModule");
 
         // --- Patient Study Module ---
+        addElementToDataset(result, dataset, new DcmAgeString(PatientAge), "1", "3", "PatientStudyModule");
         addElementToDataset(result, dataset, new DcmDecimalString(PatientSize), "1", "3", "PatientStudyModule");
         addElementToDataset(result, dataset, new DcmDecimalString(PatientWeight), "1", "3", "PatientStudyModule");
 
@@ -979,7 +985,8 @@ OFCondition DSRDocument::readXMLPatientData(const DSRXMLDocument &doc,
             else if (doc.getElementFromNodeContent(cursor, PatientID, "id").bad() &&
                      doc.getElementFromNodeContent(cursor, IssuerOfPatientID, "issuer").bad() &&
                      doc.getElementFromNodeContent(cursor, PatientSex, "sex").bad() &&
-                     /* strictly speaking, Patient's Size and Weight belong to the Study IE */
+                     /* strictly speaking, Patient's Age, Size and Weight belong to the Study IE */
+                     doc.getElementFromNodeContent(cursor, PatientAge, "age").bad() &&
                      doc.getElementFromNodeContent(cursor, PatientSize, "size").bad() &&
                      doc.getElementFromNodeContent(cursor, PatientWeight, "weight").bad())
             {
@@ -1185,7 +1192,11 @@ OFCondition DSRDocument::readXMLDocumentData(const DSRXMLDocument &doc,
                     result = readXMLVerifyingObserverData(doc, cursor.getChild(), flags);
                     /* allow absence in case of UNVERIFIED */
                     if (VerificationFlagEnum == VF_Unverified)
+                    {
+                        if (!VerifyingObserver.isEmpty())
+                            DCMSR_WARN("Verifying Observer(s) should not be present when Verification Flag is 'UNVERIFIED'");
                         result = EC_Normal;
+                    }
                 } else
                     printUnknownValueWarningMessage("VerificationFlag", tmpString.c_str());
             }
@@ -1377,7 +1388,8 @@ OFCondition DSRDocument::writeXML(STD_NAMESPACE ostream &stream,
             stream << "</birthday>" << OFendl;
         }
         writeStringFromElementToXML(stream, PatientSex, "sex", (flags & XF_writeEmptyTags) > 0);
-        /* strictly speaking, Patient's Size and Weight belong to the Study IE */
+        /* strictly speaking, Patient's Age, Size and Weight belong to the Study IE */
+        writeStringFromElementToXML(stream, PatientAge, "age", (flags & XF_writeEmptyTags) > 0);
         writeStringFromElementToXML(stream, PatientSize, "size", (flags & XF_writeEmptyTags) > 0);
         writeStringFromElementToXML(stream, PatientWeight, "weight", (flags & XF_writeEmptyTags) > 0);
         stream << "</patient>" << OFendl;
@@ -2308,6 +2320,13 @@ OFCondition DSRDocument::getPatientSex(OFString &value,
 }
 
 
+OFCondition DSRDocument::getPatientAge(OFString &value,
+                                       const signed long pos) const
+{
+    return getStringValueFromElement(PatientAge, value, pos);
+}
+
+
 OFCondition DSRDocument::getPatientSize(OFString &value,
                                         const signed long pos) const
 {
@@ -2572,6 +2591,16 @@ OFCondition DSRDocument::setPatientSex(const OFString &value,
 }
 
 
+OFCondition DSRDocument::setPatientAge(const OFString &value,
+                                       const OFBool check)
+{
+    OFCondition result = (check) ? DcmAgeString::checkStringValue(value, "1") : EC_Normal;
+    if (result.good())
+        result = PatientAge.putOFStringArray(value);
+    return result;
+}
+
+
 OFCondition DSRDocument::setPatientSize(const OFString &value,
                                         const OFBool check)
 {
@@ -2835,6 +2864,7 @@ void DSRDocument::createNewStudy()
     AccessionNumber.clear();
     StudyDescription.clear();
     /* also need to clear the attributes from the Patient Study Module */
+    PatientAge.clear();
     PatientSize.clear();
     PatientWeight.clear();
     /* the following method also creates new a study (since UID is empty) and SOP instance */
index 01dff74de005e449983c00737cac6d28d91b2ed4..691f97bfe7d53dedd0ba8abc61445e49e3e510fc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -132,7 +132,7 @@ OFBool DSRDocumentTreeNode::isShort(const size_t /*flags*/) const
 
 OFBool DSRDocumentTreeNode::hasTemplateIdentification() const
 {
-    /* mapping resource UID is optional, so do not check it */
+    /* Mapping Resource UID is optional, so do not check it */
     return !TemplateIdentifier.empty() && !MappingResource.empty();
 }
 
@@ -253,9 +253,9 @@ OFCondition DSRDocumentTreeNode::readXML(const DSRXMLDocument &doc,
                     DCMSR_WARN("Content item has invalid/incomplete template identification");
             }
         }
-        /* read concept name (not required in some cases) */
+        /* read Concept Name (not required in some cases) */
         ConceptName.readXML(doc, doc.getNamedChildNode(cursor, "concept", OFFalse /*required*/), flags);
-        /* read observation UID and date/time (optional) */
+        /* read Observation UID and date/time (optional) */
         const DSRXMLCursor childCursor = doc.getNamedChildNode(cursor, "observation", OFFalse /*required*/);
         if (childCursor.valid())
         {
@@ -356,10 +356,10 @@ OFCondition DSRDocumentTreeNode::writeXML(STD_NAMESPACE ostream &stream,
             }
         }
     }
-    /* relationship type */
+    /* Relationship Type */
     if ((RelationshipType != RT_isRoot) && !(flags & XF_relationshipTypeAsAttribute))
         writeStringValueToXML(stream, relationshipTypeToDefinedTerm(RelationshipType), "relationship", (flags & XF_writeEmptyTags) > 0);
-    /* concept name */
+    /* Concept Name */
     if (ConceptName.isValid())
     {
         if (flags & XF_codeComponentsAsAttribute)
@@ -371,7 +371,7 @@ OFCondition DSRDocumentTreeNode::writeXML(STD_NAMESPACE ostream &stream,
     }
     if (!(ObservationDateTime.empty() && ObservationUID.empty()))
     {
-        /* observation UID (optional) */
+        /* Observation UID (optional) */
         OFString tmpString;
         stream << "<observation";
         if (!ObservationUID.empty())
@@ -692,9 +692,9 @@ OFCondition DSRDocumentTreeNode::readSRDocumentContentModule(DcmItem &dataset,
                                                              const size_t flags)
 {
     OFCondition result = EC_Normal;
-    /* read DocumentRelationshipMacro */
+    /* read Document Relationship Macro */
     result = readDocumentRelationshipMacro(dataset, constraintChecker, "1" /*posString*/, flags);
-    /* read DocumentContentMacro */
+    /* read Document Content Macro */
     if (result.good())
         result = readDocumentContentMacro(dataset, "1" /*posString*/, flags);
     return result;
@@ -705,9 +705,9 @@ OFCondition DSRDocumentTreeNode::writeSRDocumentContentModule(DcmItem &dataset,
                                                               DcmStack *markedItems)
 {
     OFCondition result = EC_Normal;
-    /* write DocumentRelationshipMacro */
+    /* write Document Relationship Macro */
     result = writeDocumentRelationshipMacro(dataset, markedItems);
-    /* write DocumentContentMacro */
+    /* write Document Content Macro */
     if (result.good())
         result = writeDocumentContentMacro(dataset);
     return result;
@@ -726,16 +726,16 @@ OFCondition DSRDocumentTreeNode::readDocumentRelationshipMacro(DcmItem &dataset,
         getElementFromDataset(dataset, MACParameters);
         getElementFromDataset(dataset, DigitalSignatures);
     }
-    /* read ObservationDateTime (conditional) */
+    /* read Observation DateTime (conditional) */
     getAndCheckStringValueFromDataset(dataset, DCM_ObservationDateTime, ObservationDateTime, "1", "1C");
-    /* read ObservationUID (optional) */
+    /* read Observation UID (optional) */
     getAndCheckStringValueFromDataset(dataset, DCM_ObservationUID, ObservationUID, "1", "3");
     /* determine template identifier expected for this document */
     OFString expectedTemplateIdentifier;
     OFString expectedMappingResource;
     if (constraintChecker != NULL)
         constraintChecker->getRootTemplateIdentification(expectedTemplateIdentifier, expectedMappingResource);
-    /* read ContentTemplateSequence (conditional) */
+    /* read Content Template Sequence (conditional) */
     DcmItem *ditem = NULL;
     if (dataset.findAndGetSequenceItem(DCM_ContentTemplateSequence, ditem, 0 /*itemNum*/).good())
     {
@@ -763,6 +763,15 @@ OFCondition DSRDocumentTreeNode::readDocumentRelationshipMacro(DcmItem &dataset,
                 }
             }
         }
+        else if (!MappingResource.empty())
+        {
+            /* check whether an incorrect Mapping Resource UID is used */
+            if (MappingResourceUID == UID_DICOMContentMappingResource)
+            {
+                DCMSR_WARN("Incorrect value for Mapping Resource UID (" << MappingResourceUID << "), "
+                    << "should only be used for 'DCMR' and not for '" << MappingResource << "'");
+            }
+        }
         /* check whether the expected template (if known) has been used */
         if (!expectedTemplateIdentifier.empty())
         {
@@ -788,7 +797,7 @@ OFCondition DSRDocumentTreeNode::readDocumentRelationshipMacro(DcmItem &dataset,
         DCMSR_WARN("Content Template Sequence missing or empty, Template Identifier "
             << expectedTemplateIdentifier << " (" << expectedMappingResource << ") expected");
     }
-    /* read ContentSequence */
+    /* read Content Sequence */
     if (result.good())
         result = readContentSequence(dataset, constraintChecker, posString, flags);
     return result;
@@ -810,12 +819,12 @@ OFCondition DSRDocumentTreeNode::writeDocumentRelationshipMacro(DcmItem &dataset
     /* add to marked items stack */
     if (MarkFlag && (markedItems != NULL))
         markedItems->push(&dataset);
-    /* write ObservationDateTime (conditional) */
+    /* write Observation DateTime (conditional) */
     result = putStringValueToDataset(dataset, DCM_ObservationDateTime, ObservationDateTime, OFFalse /*allowEmpty*/);
-    /* write ObservationUID (optional) */
+    /* write Observation UID (optional) */
     if (result.good())
         result = putStringValueToDataset(dataset, DCM_ObservationUID, ObservationUID, OFFalse /*allowEmpty*/);
-    /* write ContentTemplateSequence (conditional) */
+    /* write Content Template Sequence (conditional) */
     if (result.good())
     {
         if (hasTemplateIdentification())
@@ -846,9 +855,9 @@ OFCondition DSRDocumentTreeNode::readDocumentContentMacro(DcmItem &dataset,
                                                           const size_t flags)
 {
     OFCondition result = EC_Normal;
-    /* skip reading ValueType, already done somewhere else */
+    /* skip reading Value Type, already done somewhere else */
 
-    /* read ConceptNameCodeSequence */
+    /* read Concept Name Code Sequence */
     if (RelationshipType == RT_isRoot)
     {
         /* the concept name is required for the root container */
@@ -861,7 +870,7 @@ OFCondition DSRDocumentTreeNode::readDocumentContentMacro(DcmItem &dataset,
     {
         if (result.bad())
             DCMSR_DEBUG("Ignoring content item error because of read flag");
-        /* read ContentItem (depending on ValueType) */
+        /* read Content Item (depending on Value Type) */
         result = readContentItem(dataset, flags);
     }
     /* check for validity, after reading */
@@ -894,9 +903,9 @@ OFCondition DSRDocumentTreeNode::readDocumentContentMacro(DcmItem &dataset,
 OFCondition DSRDocumentTreeNode::writeDocumentContentMacro(DcmItem &dataset) const
 {
     OFCondition result = EC_Normal;
-    /* write ValueType */
+    /* write Value Type */
     result = putStringValueToDataset(dataset, DCM_ValueType, valueTypeToDefinedTerm(ValueType));
-    /* write ConceptNameCodeSequence */
+    /* write Concept Name Code Sequence */
     if (result.good())
     {
         if (ConceptName.isValid())
@@ -907,7 +916,7 @@ OFCondition DSRDocumentTreeNode::writeDocumentContentMacro(DcmItem &dataset) con
         /* check for validity, before writing */
         if (!isValid())
             printInvalidContentItemMessage("Writing", this);
-        /* write ContentItem (depending on ValueType) */
+        /* write Content Item (depending on Value Type) */
         result = writeContentItem(dataset);
     }
     return result;
@@ -964,7 +973,7 @@ OFCondition DSRDocumentTreeNode::readContentSequence(DcmItem &dataset,
 {
     OFCondition result = EC_Normal;
     DcmSequenceOfItems *dseq = NULL;
-    /* read ContentSequence (might be absent or empty) */
+    /* read Content Sequence (might be absent or empty) */
     if (dataset.findAndGetSequence(DCM_ContentSequence, dseq).good())
     {
         OFString tmpString;
@@ -987,7 +996,7 @@ OFCondition DSRDocumentTreeNode::readContentSequence(DcmItem &dataset,
             location += numberToString(OFstatic_cast(size_t, i + 1), buffer, sizeof(buffer));
             if (flags & RF_showCurrentlyProcessedItem)
                 DCMSR_INFO("Processing content item " << location);
-            /* read RelationshipType */
+            /* read Relationship Type */
             result = getAndCheckStringValueFromDataset(*ditem, DCM_RelationshipType, tmpString, "1", "1", "content item");
             if (result.good() || (flags & RF_acceptUnknownRelationshipType))
             {
@@ -1005,14 +1014,14 @@ OFCondition DSRDocumentTreeNode::readContentSequence(DcmItem &dataset,
                 {
                     /* create new node (by-reference, no constraint checker required) */
                     result = createAndAppendNewNode(node, relationshipType, VT_byReference);
-                    /* read ReferencedContentItemIdentifier (again) */
+                    /* read Referenced Content Item Identifier (again) */
                     if (result.good())
                     {
                         newNode = node;
                         result = node->readContentItem(*ditem, flags);
                     }
                 } else {
-                    /* read ValueType (from DocumentContentMacro) - required to create new node */
+                    /* read Value Type (from Document Content Macro) - required to create new node */
                     result = getAndCheckStringValueFromDataset(*ditem, DCM_ValueType, tmpString, "1", "1", "content item");
                     if (result.good())
                     {
@@ -1023,12 +1032,12 @@ OFCondition DSRDocumentTreeNode::readContentSequence(DcmItem &dataset,
                         {
                             /* create new node (by-value) */
                             result = createAndAppendNewNode(node, relationshipType, valueType, (flags & RF_ignoreRelationshipConstraints) ? NULL : constraintChecker);
-                            /* read RelationshipMacro */
+                            /* read Relationship Macro */
                             if (result.good())
                             {
                                 newNode = node;
                                 result = node->readDocumentRelationshipMacro(*ditem, constraintChecker, location, flags);
-                                /* read DocumentContentMacro */
+                                /* read Document Content Macro */
                                 if (result.good())
                                     result = node->readDocumentContentMacro(*ditem, location.c_str(), flags);
                             } else {
@@ -1079,7 +1088,7 @@ OFCondition DSRDocumentTreeNode::writeContentSequence(DcmItem &dataset,
     DSRDocumentTreeNodeCursor cursor(getDown());
     if (cursor.isValid())
     {
-        /* write ContentSequence */
+        /* write Content Sequence */
         DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_ContentSequence);
         if (dseq != NULL)
         {
@@ -1091,19 +1100,19 @@ OFCondition DSRDocumentTreeNode::writeContentSequence(DcmItem &dataset,
                 ditem = new DcmItem();
                 if (ditem != NULL)
                 {
-                    /* write RelationshipType */
+                    /* write Relationship Type */
                     result = putStringValueToDataset(*ditem, DCM_RelationshipType, relationshipTypeToDefinedTerm(node->getRelationshipType()));
                     /* check for by-reference relationship */
                     if (node->getValueType() == VT_byReference)
                     {
-                        /* write ReferencedContentItemIdentifier */
+                        /* write Referenced Content Item Identifier */
                         if (result.good())
                             result = node->writeContentItem(*ditem);
                     } else {    // by-value
-                        /* write RelationshipMacro */
+                        /* write Relationship Macro */
                         if (result.good())
                             result = node->writeDocumentRelationshipMacro(*ditem, markedItems);
-                        /* write DocumentContentMacro */
+                        /* write Document Content Macro */
                         if (result.good())
                             node->writeDocumentContentMacro(*ditem);
                     }
@@ -1141,7 +1150,7 @@ OFCondition DSRDocumentTreeNode::renderHTMLConceptName(STD_NAMESPACE ostream &do
         if (!ConceptName.getCodeMeaning().empty())
         {
             docStream << "<b>";
-            /* render ConceptName & Code (if valid) */
+            /* render Concept Name & Code (if valid) */
             ConceptName.renderHTML(docStream, flags, (flags & HF_renderConceptNameCodes) && ConceptName.isValid() /*fullCode*/);
             docStream << ":</b>";
             writeLine = OFTrue;
@@ -1149,7 +1158,7 @@ OFCondition DSRDocumentTreeNode::renderHTMLConceptName(STD_NAMESPACE ostream &do
         else if (flags & HF_currentlyInsideAnnex)
         {
             docStream << "<b>";
-            /* render ValueType only */
+            /* render Value Type only */
             docStream << valueTypeToReadableName(ValueType);
             docStream << ":</b>";
             writeLine = OFTrue;
index 50033558a38161e29d52efe55075ec8b68d299d9..00b548e215b3589bb14396e1f6985acb9b09d8fa 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -89,9 +89,8 @@ DSRImageReferenceValue::DSRImageReferenceValue(const DSRImageReferenceValue &ref
 {
     /* do not check values since this would be unexpected to the user */
 
-    /* create copy of icon image (if any), first frame only */
-    if (referenceValue.IconImage != NULL)
-        IconImage = referenceValue.IconImage->createDicomImage(0 /*fstart*/, 1 /*fcount*/);
+    /* create copy of icon image (if any) */
+    copyIconImage(referenceValue.IconImage);
 }
 
 
@@ -124,8 +123,8 @@ DSRImageReferenceValue &DSRImageReferenceValue::operator=(const DSRImageReferenc
         SegmentList = referenceValue.SegmentList;
         PresentationState = referenceValue.PresentationState;
         RealWorldValueMapping = referenceValue.RealWorldValueMapping;
-        /* create copy of icon image (if any), first frame only */
-        IconImage = (referenceValue.IconImage != NULL) ? referenceValue.IconImage->createDicomImage(0 /*fstart*/, 1 /*fcount*/) : NULL;
+        /* create copy of icon image (if any) */
+        copyIconImage(referenceValue.IconImage);
     }
     return *this;
 }
@@ -182,6 +181,12 @@ OFBool DSRImageReferenceValue::isSegmentation() const
 }
 
 
+OFBool DSRImageReferenceValue::hasIconImage() const
+{
+    return (IconImage != NULL);
+}
+
+
 OFCondition DSRImageReferenceValue::print(STD_NAMESPACE ostream &stream,
                                           const size_t flags) const
 {
@@ -632,6 +637,8 @@ OFCondition DSRImageReferenceValue::setValue(const DSRImageReferenceValue &refer
         /* ignore status (return value) since the references are optional */
         setPresentationState(referenceValue.PresentationState, check);
         setRealWorldValueMapping(referenceValue.RealWorldValueMapping, check);
+        /* create copy of icon image (if any) */
+        copyIconImage(referenceValue.IconImage);
     }
     return result;
 }
@@ -785,6 +792,18 @@ OFCondition DSRImageReferenceValue::checkCurrentValue(const OFBool reportWarning
 }
 
 
+void DSRImageReferenceValue::copyIconImage(DicomImage *image)
+{
+    /* first, delete the current icon image */
+    delete IconImage;
+    /* then create a copy of the given icon image (first frame only) */
+    if (image != NULL)
+        IconImage = image->createDicomImage(0 /*fstart*/, 1 /*fcount*/);
+    else
+        IconImage = NULL;
+}
+
+
 // comparison operators
 
 OFBool operator==(const DSRImageReferenceValue &lhs,
index 37525c9d05c451ee97b3c5bed24e85f84f0f1998..9c21f9330fea736e7424e964e610f1225d474974 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -238,11 +238,10 @@ OFCondition DSRNumericMeasurementValue::writeXML(STD_NAMESPACE ostream &stream,
         stream << "<float>";
         if (hasFloating)
         {
-            /* increase default precision */
-            const STD_NAMESPACE streamsize oldPrecision = stream.precision(8);
-            stream << floatValue;
-            /* reset i/o manipulators */
-            stream.precision(oldPrecision);
+            char buffer[64];
+            /* need to convert float to avoid problems with decimal point and "-nan" */
+            OFStandard::ftoa(buffer, sizeof(buffer), floatValue, 0, 0, -2 /* print enough digits to permit lossless conversion back to FD */);
+            stream << buffer;
         }
         stream << "</float>" << OFendl;
     }
index 1774c95779cfb866d4fd4258a1d1b38f243c7e40..5b813915cf269d9042eaf0b7ca0904501b16fc0d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -400,7 +400,9 @@ static const S_PresentationStateTypeNameMap PresentationStateTypeNameMap[] =
     {DSRTypes::PT_VolumeRendering,          UID_VolumeRenderingVolumetricPresentationStateStorage,          "VR-VPS"},
     {DSRTypes::PT_SegmentedVolumeRendering, UID_SegmentedVolumeRenderingVolumetricPresentationStateStorage, "SVR-VPS"},
     {DSRTypes::PT_MultipleVolumeRendering,  UID_MultipleVolumeRenderingVolumetricPresentationStateStorage,  "MVR-VPS"},
-    {DSRTypes::PT_VariableModalityLUT,      UID_VariableModalityLUTSoftcopyPresentationStateStorage,        "VML-SPS"}
+    {DSRTypes::PT_VariableModalityLUT,      UID_VariableModalityLUTSoftcopyPresentationStateStorage,        "VML-SPS"},
+    {DSRTypes::PT_Waveform,                 UID_WaveformPresentationStateStorage,                           "WPS"},
+    {DSRTypes::PT_WaveformAcquisition,      UID_WaveformAcquisitionPresentationStateStorage,                "WAPS"}
 };
 
 
index 74f2ad703328f5db47f0e6f596cb30f574262d9e..d157e61e95980559520cb6ff1f5ae23f732e95c6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2003-2024, OFFIS e.V.
+ *  Copyright (C) 2003-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #endif /* LIBXML_SCHEMAS_ENABLED */
 
 // This function is also used in xml2dcm, try to stay in sync!
-#if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
 extern "C" void errorFunction(void * ctx, const char *msg, ...)
-#else
-extern "C" void errorFunction(void * /* ctx */, const char *msg, ...)
-#endif
 {
     OFLogger xmlLogger = OFLog::getLogger("dcmtk.dcmsr.libxml");
 
     if (!xmlLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
         return;
 
-#if defined(HAVE_VSNPRINTF) && defined(HAVE_PROTOTYPE_VSNPRINTF)
     // libxml calls us multiple times for one line of log output which would
     // result in garbled output. To avoid this, we buffer the output in a local
     // string in the caller which we get through our 'ctx' parameter. Then, we
@@ -76,23 +71,6 @@ extern "C" void errorFunction(void * /* ctx */, const char *msg, ...)
 
         pos = buffer.find('\n');
     }
-#else
-    // No vsnprint, but at least vfprintf. Output the messages directly to stderr.
-    va_list ap;
-    va_start(ap, msg);
-#ifdef HAVE_PROTOTYPE_STD__VFPRINTF
-    std::vfprintf(stderr, msg, ap);
-#else
-    vfprintf(stderr, msg, ap);
-#endif
-    va_end(ap);
-#endif
-
-#ifndef HAVE_VSNPRINTF
-    // Only the vsnprintf() branch above uses 'buffer' which means the compiler
-    // would warn about an unused variable if HAVE_VSNPRINTF is undefined.
-    buffer += "";
-#endif
 }
 
 #endif /* WITH_LIBXML */
index f4ecd4cc343500b5016fa43bde07a391fb6cacad..26f043c8e9772a93fa20f20eb642c0a5aa068a35 100644 (file)
@@ -7,6 +7,7 @@ DCMTK_ADD_TEST_EXECUTABLE(dcmsr_tests
   tsrdoc.cc
   tsrdoctr.cc
   tsrlist.cc
+  tsrimgvl.cc
   tsrnumvl.cc
   tsrtpl.cc
   tsrtree.cc
index 7749800cbbeb2afef93eba9b077dd14eeb867a70..c8103c696d75e1a7f4885ae59e8130a9dc08a192 100644 (file)
@@ -87,8 +87,9 @@ mkreport.o: mkreport.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -118,7 +119,6 @@ mkreport.o: mkreport.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcpixseq.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcofsetl.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrae.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrur.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
@@ -290,8 +290,9 @@ tsrcmr.o: tsrcmr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -506,8 +507,9 @@ tsrdoc.o: tsrdoc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -611,8 +613,9 @@ tsrdoctr.o: tsrdoctr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
@@ -626,6 +629,85 @@ tsrdoctr.o: tsrdoctr.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrreftn.h ../include/dcmtk/dcmsr/dsrimgtn.h \
  ../include/dcmtk/dcmsr/dsrnumtn.h ../include/dcmtk/dcmsr/dsrtextn.h \
  ../include/dcmtk/dcmsr/dsrstrvl.h
+tsrimgvl.o: tsrimgvl.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../include/dcmtk/dcmsr/dsrimgvl.h ../include/dcmtk/dcmsr/dsrtypes.h \
+ ../include/dcmtk/dcmsr/dsdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../include/dcmtk/dcmsr/dsrcomvl.h ../include/dcmtk/dcmsr/dsrimgfr.h \
+ ../include/dcmtk/dcmsr/dsrtlist.h ../include/dcmtk/dcmsr/dsrimgse.h \
+ ../include/dcmtk/dcmsr/dsrimgtn.h ../include/dcmtk/dcmsr/dsrdoctn.h \
+ ../include/dcmtk/dcmsr/dsrtree.h ../include/dcmtk/dcmsr/dsrtncsr.h \
+ ../include/dcmtk/dcmsr/dsrposcn.h ../include/dcmtk/dcmsr/dsrtnant.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstack.h \
+ ../include/dcmtk/dcmsr/dsrcodvl.h ../include/dcmtk/dcmsr/codes/dcm.h
 tsrlist.o: tsrlist.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../ofstd/include/dcmtk/ofstd/oftest.h \
  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
@@ -849,8 +931,9 @@ tsrtpl.o: tsrtpl.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/dcmsr/dsrwavch.h ../include/dcmtk/dcmsr/dsrrtpl.h \
  ../include/dcmtk/dcmsr/dsrctpl.h ../include/dcmtk/dcmsr/dsrsoprf.h \
  ../include/dcmtk/dcmsr/dsrrefin.h ../include/dcmtk/dcmsr/dsrcsidl.h \
- ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvras.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrda.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
index f22d07cf1f29cbfe23b249d8aed935467b65f2a5..d0796ec71fae24cbec8a93e115029e4b29c4eafa 100644 (file)
@@ -27,8 +27,8 @@ LIBDIRS = -L$(top_srcdir)/libcmr -L$(top_srcdir)/libsrc -L$(ofstddir)/libsrc \
 LOCALLIBS = -lcmr -ldcmsr -ldcmimage -ldcmimgle -ldcmdata -loflog -lofstd -loficonv \
        $(TIFFLIBS) $(PNGLIBS) $(XMLLIBS) $(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS)
 
-tstobjs = tests.o tsrtree.o tsrdoctr.o tsrdoc.o tsrcodvl.o tsrnumvl.o tsrtpl.o \
-       tsrcmr.o tsrlist.o
+tstobjs = tests.o tsrtree.o tsrdoctr.o tsrdoc.o tsrcodvl.o tsrimgvl.o tsrnumvl.o \
+       tsrtpl.o tsrcmr.o tsrlist.o
 objs = mkreport.o $(tstobjs)
 progs = mkreport tests
 
index 1513148afd3d91df6b8d26e262bd7d066c553a53..a79bb98d33b482f933167c8d7ba77e239c297f31 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2022, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -83,6 +83,8 @@ OFTEST_REGISTER(dcmsr_determineCodeValueType);
 OFTEST_REGISTER(dcmsr_writeCodeSequence);
 OFTEST_REGISTER(dcmsr_compareCodedEntry);
 OFTEST_REGISTER(dcmsr_useBasicCodedEntry);
+OFTEST_REGISTER(dcmsr_createMonochromeIconImage);
+OFTEST_REGISTER(dcmsr_createColorIconImage);
 OFTEST_REGISTER(dcmsr_setNumericMeasurementValue);
 OFTEST_REGISTER(dcmsr_emptyMeasurementValueSequence);
 OFTEST_REGISTER(dcmsr_setAndGetFloatingPointRepresentation);
index 0b26f46fb0de6e4ad38219644552c4eb87621288..8d619ce534f0d97b09643d1bb9b334b6597a6d26 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2022, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2015-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -66,6 +66,8 @@ OFTEST(dcmsr_CID29e_AcquisitionModality)
     OFCHECK(ctxGroup.mapModality("XYZ").isEmpty());
     OFCHECK(ctxGroup.mapModality("ABC", codedEntry) == SR_EC_UnsupportedValue);
     OFCHECK(ctxGroup.selectValue("").bad());
+    /* also check the keyword of the context group */
+    OFCHECK_EQUAL(ctxGroup.getKeyword(), "AcquisitionModality");
 }
 
 
@@ -81,6 +83,8 @@ OFTEST(dcmsr_CID42_NumericValueQualifier)
     OFCHECK(ctxGroup.findCodedEntry(DSRBasicCodedEntry("", "99TEST", "Some invalid test code")).bad());
     OFCHECK(ctxGroup.findCodedEntry(DSRBasicCodedEntry("0815", "99TEST", "-")).good());
     OFCHECK(ctxGroup.findCodedEntry(DSRBasicCodedEntry("", "", "")).bad());
+    /* also check the keyword of the context group */
+    OFCHECK_EQUAL(ctxGroup.getKeyword(), "NumericValueQualifier");
 }
 
 
@@ -97,6 +101,8 @@ OFTEST(dcmsr_CID244e_Laterality)
     OFCHECK(!ctxGroup.mapImageLaterality("XYZ").isValid());
     OFCHECK(ctxGroup.mapImageLaterality("ABC", codedEntry) == SR_EC_InvalidValue);
     OFCHECK(ctxGroup.selectValue("").bad());
+    /* also check the keyword of the context group */
+    OFCHECK_EQUAL(ctxGroup.getKeyword(), "Laterality");
 }
 
 
index f8c76bc894c393bb74a158f280866311e32098f7..e96f73026281a85046110aae8010219e2b15aa26 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2014-2021, J. Riesmeier, Oldenburg, Germany
+ *  Copyright (C) 2014-2025, J. Riesmeier, Oldenburg, Germany
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -49,6 +49,9 @@ OFTEST(dcmsr_setAndGetPatientData)
     OFCHECK(doc.getPatientSex(value).good());
     OFCHECK_EQUAL(value, "M");
     /* also check some recently introduced attributes */
+    OFCHECK(doc.setPatientAge("042Y").good());
+    OFCHECK(doc.getPatientAge(value).good());
+    OFCHECK_EQUAL(value, "042Y");
     OFCHECK(doc.setPatientSize("1.88").good());
     OFCHECK(doc.getPatientSize(value).good());
     OFCHECK_EQUAL(value, "1.88");
diff --git a/dcmsr/tests/tsrimgvl.cc b/dcmsr/tests/tsrimgvl.cc
new file mode 100644 (file)
index 0000000..ae14cb0
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *
+ *  Copyright (C) 2025, J. Riesmeier, Oldenburg, Germany
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation are maintained by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module: dcmsr
+ *
+ *  Author: Joerg Riesmeier
+ *
+ *  Purpose:
+ *    test program for class DSRImageReferenceValue
+ *
+ */
+
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+
+#include "dcmtk/ofstd/oftest.h"
+
+#include "dcmtk/dcmdata/dcuid.h"
+#include "dcmtk/dcmdata/dcdatset.h"
+#include "dcmtk/dcmdata/dcdeftag.h"
+#include "dcmtk/dcmdata/dctypes.h"
+
+#include "dcmtk/dcmsr/dsrimgvl.h"
+#include "dcmtk/dcmsr/dsrimgtn.h"
+#include "dcmtk/dcmsr/codes/dcm.h"
+
+
+OFTEST(dcmsr_createMonochromeIconImage)
+{
+    DSRImageReferenceValue imgValue(UID_CTImageStorage, "1.2.3.4.5.6.7.8.9.0.98");
+    OFCHECK(!imgValue.hasIconImage());
+
+    /* create a monochrome image dataset */
+    DcmDataset dataset;
+    Uint8 pixelData[256];
+    for (int i = 0; i < 256; i++)
+        pixelData[i] = OFstatic_cast(Uint8, i);
+    OFCHECK(dataset.putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2").good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_SamplesPerPixel, 1).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_PixelRepresentation, 0).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_Rows, 16).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_Columns, 16).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_BitsAllocated, 8).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_BitsStored, 8).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_HighBit, 7).good());
+    OFCHECK(dataset.putAndInsertUint8Array(DCM_PixelData, pixelData, sizeof(pixelData)).good());
+
+    /* create an icon image with 64x64 pixels */
+    OFCHECK(imgValue.createIconImage(&dataset, EXS_Unknown /*xfer*/, 0 /*frame*/, 64 /*width*/, 64 /*height*/).good());
+    OFCHECK(imgValue.hasIconImage());
+
+    /* set value to image tree node and write to item */
+    DcmItem item;
+    DSRImageTreeNode imgNode(DSRTypes::RT_contains);
+    OFCHECK(imgNode.setConceptName(CODE_DCM_BestInSet).good());
+    OFCHECK(imgNode.setValue(imgValue).good());
+    OFCHECK(imgNode.hasIconImage());
+    OFCHECK(imgNode.write(item).good());
+    /* output content of the item (in debug mode only) */
+    if (DCM_dcmsrLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+        item.print(COUT, DCMTypes::PF_shortenLongTagValues /*flags*/, 2 /*level*/);
+
+    /* delete the icon image */
+    imgNode.deleteIconImage();
+    OFCHECK(!imgNode.hasIconImage());
+}
+
+
+OFTEST(dcmsr_createColorIconImage)
+{
+    DSRImageReferenceValue imgValue(UID_CTImageStorage, "1.2.3.4.5.6.7.8.9.0.99");
+    OFCHECK(!imgValue.hasIconImage());
+
+    /* create a color image dataset */
+    DcmDataset dataset;
+    Uint8 pixelData[256][3];
+    for (int i = 0; i < 256; i++)
+    {
+        pixelData[i][0] = OFstatic_cast(Uint8, i);
+        pixelData[i][1] = OFstatic_cast(Uint8, i);
+        pixelData[i][2] = OFstatic_cast(Uint8, i);
+    }
+    OFCHECK(dataset.putAndInsertString(DCM_PhotometricInterpretation, "RGB").good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_SamplesPerPixel, 3).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_PixelRepresentation, 0).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_PlanarConfiguration, 0).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_Rows, 16).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_Columns, 16).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_BitsAllocated, 8).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_BitsStored, 8).good());
+    OFCHECK(dataset.putAndInsertUint16(DCM_HighBit, 7).good());
+    OFCHECK(dataset.putAndInsertUint8Array(DCM_PixelData, pixelData[0], sizeof(pixelData)).good());
+
+    /* create an icon image with 64x64 pixels */
+    OFCHECK(imgValue.createIconImage(&dataset, EXS_Unknown /*xfer*/, 0 /*frame*/, 64 /*width*/, 64 /*height*/).good());
+    OFCHECK(imgValue.hasIconImage());
+
+    /* set value to image tree node and write to item */
+    DcmItem item;
+    DSRImageTreeNode imgNode(DSRTypes::RT_hasProperties);
+    OFCHECK(imgNode.setConceptName(CODE_DCM_BestIllustrationOfFinding).good());
+    OFCHECK(imgNode.setValue(imgValue).good());
+    OFCHECK(imgNode.hasIconImage());
+    OFCHECK(imgNode.write(item).good());
+    /* output content of the item (in debug mode only) */
+    if (DCM_dcmsrLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
+        item.print(COUT, DCMTypes::PF_shortenLongTagValues /*flags*/, 2 /*level*/);
+
+    /* delete the icon image */
+    imgNode.deleteIconImage();
+    OFCHECK(!imgNode.hasIconImage());
+}
index 32fbda46adf838191aa140b24e6d10d084b03f2d..be442c18f918cd22267ca8c6a994fb4c53c0bd8a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2010-2023, OFFIS e.V.
+ *  Copyright (C) 2010-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -118,6 +118,12 @@ public:
    */
   virtual OFCondition setTLSProfile(DcmTLSSecurityProfile profile);
 
+  /** activate the ciphersuites that have been added to the list of ciphersuites
+   *  for TLS negotiation. Caller must ensure that initNetwork() is executed before this call.
+   *  @return EC_Normal if successful, an error code otherwise
+   */
+  virtual OFCondition activateCipherSuites();
+
   /** adds a ciphersuite to the list of ciphersuites for TLS negotiation.
    *  Caller must ensure that initNetwork() is executed before this call.
    *  It is the responsibility of the user to ensure that the added ciphersuite
index 61d381af08fa267d3d01089557c1f41b6987630e..8f08b57f26b290d0d8eceb8bc0e1465f0162921c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2024, OFFIS e.V.
+ *  Copyright (C) 2018-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -180,7 +180,7 @@ static const DcmCipherSuiteList globalTLS13CipherSuiteList[] =
     {"TLS_AES_256_GCM_SHA384",                        TLS1_3_RFC_AES_256_GCM_SHA384,                   TPV_TLSv13, TKE_TLSv13,     TCA_TLSv13, TCE_AES,      TCM_SHA384,  TKM_GCM,  256, 256},
 };
 
-#define GLOBAL_NUM_TLS13_CIPHERSUITES (sizeof(globalCipherSuiteList)/sizeof(DcmCipherSuiteList))
+#define GLOBAL_NUM_TLS13_CIPHERSUITES (sizeof(globalTLS13CipherSuiteList)/sizeof(DcmCipherSuiteList))
 
 
 const size_t DcmTLSCiphersuiteHandler::unknownCipherSuiteIndex = (size_t) -1;
index 80fbd8508565f7e90e8cca5a6bcf3026df1b1395..c3424b7264beb0c2998fd7806e175a4785c70395 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018-2024, OFFIS e.V.
+ *  Copyright (C) 2018-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -32,7 +32,7 @@ BEGIN_EXTERN_C
 #include <openssl/tls1.h>
 END_EXTERN_C
 
-/* check if we fulfil all requirements for implementing the 
+/* check if we fulfil all requirements for implementing the
  * Modified BCP 195 RFC 8996 TLS Profile. With DICOM CP 2311
  * making support for Camellia in GCM mode optional, this is now rather simple.
  */
index a9aff68f2bfb7c33211dc16459fa2e044f2b4cd7..5b84a5ded6b578052673eac905f81492f8c7d687 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2010-2023, OFFIS e.V.
+ *  Copyright (C) 2010-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -268,6 +268,15 @@ OFCondition DcmTLSSCU::setTLSProfile(DcmTLSSecurityProfile profile)
   } else return EC_IllegalCall;
 }
 
+OFCondition DcmTLSSCU::activateCipherSuites()
+{
+  if (m_tLayer)
+  {
+    return m_tLayer->activateCipherSuites();
+  }
+  return EC_IllegalCall;
+}
+
 void DcmTLSSCU::setReadSeedFile(const OFString& seedFile)
 {
   m_readSeedFile = seedFile;
index 92f37f79af2531129152c4fd342edfe79994cf7a..19c049434a5d3f3fba67e66facbba75252a7fb1d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2024, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -34,9 +34,7 @@ BEGIN_EXTERN_C
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
index 6e9b80fd274fc5bd9a569edcd5ade3176adf84d6..95248b21807b68ea1eaea8e95896f2305e0947dd 100644 (file)
@@ -2,7 +2,7 @@
 DCMTK_ADD_TEST_EXECUTABLE(dcmtls_tests tests.cc tscuscptls.cc)
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(dcmtls_tests dcmnet dcmtls)
+DCMTK_TARGET_LINK_MODULES(dcmtls_tests dcmtls)
 
 # This macro parses tests.cc and registers all tests
 DCMTK_ADD_TESTS(dcmtls)
index 119c6a1a0e9c3ac5c6914325728810d12b00848e..9017c37e05e7b9c031b3ee56229d2e55a11b25a5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2019-2023, OFFIS e.V.
+ *  Copyright (C) 2019-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
     return; \
 } while (0)
 
-/** Method that ensures that the current thread is actually sleeping for the
- *  defined number of seconds (at least).
- *  The problem with the regular sleep() function called from OFStandard::sleep
- *  is that it might be interrupted by signals or a network timeout (depending
- *  on the operating system). This methods re-executes OFStandard's sleep method
- *  until the desired number of seconds have elapsed.
- *  @param sleep The number of seconds to sleep (at least)
- */
-static void force_sleep(Uint32 sleep)
-{
-    OFTimer timer;
-    double elapsed = timer.getDiff();
-    while (elapsed < (double)sleep)
-    {
-        // Use ceiling since otherwise we could wait too short
-        OFStandard::sleep(OFstatic_cast(unsigned int, ceil(sleep-elapsed)));
-        elapsed = timer.getDiff();
-    }
-}
-
+const size_t NUM_THREADS = 20;
 
 /** TestSCP derived from DcmSCP in order to test TLS functionality
  *  through function setTransportLayer of DcmSCPConfig.
@@ -151,6 +132,7 @@ protected:
         m_is_running = OFTrue;
         m_listen_result = listen();
         m_is_running = OFFalse;
+        DCMNET_DEBUG("TestPool: SCP Pool thread stopped, listen() returned: " << m_listen_result.text());
     }
 };
 
@@ -347,7 +329,7 @@ OFTEST_FLAGS(dcmtls_scp_tls, EF_None)
       port_number = 0xF000 + (rnd.getRND16() & 0xFFF);
       config.setPort(port_number);
       scp.start();
-      force_sleep(2); // wait 2 seconds for the SCP process to start
+      OFStandard::forceSleep(2); // wait 2 seconds for the SCP process to start
       memory_barrier.lock();
       memory_barrier.unlock();
     }
@@ -417,26 +399,23 @@ OFTEST_FLAGS(dcmtls_scp_pool_tls, EF_None)
     xfers.push_back(UID_LittleEndianImplicitTransferSyntax);
     OFCHECK(config.addPresentationContext(UID_VerificationSOPClass, xfers, ASC_SC_ROLE_DEFAULT).good());
     config.setTransportLayer(&scpTlsLayer);
-    pool.setMaxThreads(20);
+    pool.setMaxThreads(NUM_THREADS);
 
     // Ensure server is up and listening
     int i = 0;
     Uint16 port_number = 0;
-    OFMutex memory_barrier;
     do
     {
       // generate a random port number between 61440 (0xF000) and 65535
       port_number = 0xF000 + (rnd.getRND16() & 0xFFF);
       config.setPort(port_number);
       pool.start();
-      force_sleep(2); // wait 2 seconds for the SCP process to start
-      memory_barrier.lock();
-      memory_barrier.unlock();
+      OFStandard::forceSleep(2); // wait 2 seconds for the SCP process to start
     }
     while ((i++ < 5) && (! pool.m_is_running)); // try up to 5 port numbers before giving up
-    if (! pool.m_is_running) BAILOUT("Start of the SCP thread ppol failed: " << pool.m_listen_result.text());
+    if (! pool.m_is_running) BAILOUT("Start of the SCP thread pool failed: " << pool.m_listen_result.text());
 
-    OFVector<TestTLSSCU*> scus(20);
+    OFVector<TestTLSSCU*> scus(NUM_THREADS);
     OFVector<DcmTLSTransportLayer*> scuTlsLayers;
     for (OFVector<TestTLSSCU*>::iterator it1 = scus.begin(); it1 != scus.end(); ++it1)
     {
@@ -460,7 +439,7 @@ OFTEST_FLAGS(dcmtls_scp_pool_tls, EF_None)
 
     // "ensure" the pool is initialized before any SCU starts connecting to it. The initialization
     // can take a couple of seconds on older systems, e.g. debian i368.
-    force_sleep(5);
+    OFStandard::forceSleep(5);
 
     for (OFVector<TestTLSSCU*>::const_iterator it2 = scus.begin(); it2 != scus.end(); ++it2)
     {
index 504b52090b9f9f8c3749148ea8ba8b32da471c9d..5fa159bfae844af0878cc1ef063c628e29c7a543 100644 (file)
@@ -5,6 +5,6 @@ project(dcmtract)
 include_directories("${dcmtract_SOURCE_DIR}/include" "${dcmiod_SOURCE_DIR}/include" "${dcmdata_SOURCE_DIR}/include" "${ofstd_SOURCE_DIR}/include" "${oflog_SOURCE_DIR}/include" ${ZLIB_INCDIR})
 
 # recurse into subdirectories
-foreach(SUBDIR libsrc include)
+foreach(SUBDIR libsrc include tests)
   add_subdirectory(${SUBDIR})
 endforeach()
index 37ed330916fa8fa12479d461ca1c51ac4f28182d..3cf51b3626dbd40c6936c8ff866e8452b27079db 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2022, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -260,6 +260,7 @@ public:
    *          (must be either 0, 1 or numPoints)
    *  @param  result Returns the resulting Track if creation was successful,
    *          error otherwise
+   *  @return EC_Normal if successful, error code otherwise
    */
   virtual OFCondition addTrack(const Float32* pointData,
                                const size_t numPoints,
index 809922ac109180e059b4f33896dfdff1c5e36016..4eaa67fc765bb8158ee3f6a5a9fcad4bc60af6fa 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -66,6 +66,8 @@ extern DCMTK_DCMTRACT_EXPORT   const OFConditionConst     TRC_EC_MeasurementData
 extern DCMTK_DCMTRACT_EXPORT   const OFConditionConst     TRC_EC_InvalidStatisticData;
 /// Invalid Track Data
 extern DCMTK_DCMTRACT_EXPORT   const OFConditionConst     TRC_EC_InvalidTrackData;
+/// Invalid Content Identification
+extern DCMTK_DCMTRACT_EXPORT   const OFConditionConst     TRC_EC_InvalidContentIdentification;
 
 /**
  * Types specific to this module
index 3844a534edd7c23a956a5f7e5537926a4a747dd7..924ec9cda446fbd6131046ab827587e38f070bf6 100644 (file)
@@ -65,6 +65,7 @@ trcmeasurement.o: trcmeasurement.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -148,6 +149,7 @@ trcmodtractresults.o: trcmodtractresults.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -236,6 +238,7 @@ trcstatistic.o: trcstatistic.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -316,6 +319,7 @@ trctrack.o: trctrack.cc ../../config/include/dcmtk/config/osconfig.h \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../include/dcmtk/dcmtract/trctypes.h ../include/dcmtk/dcmtract/trcdef.h \
  ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
@@ -390,6 +394,7 @@ trctrackset.o: trctrackset.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
@@ -475,6 +480,7 @@ trctractographyresults.o: trctractographyresults.cc \
  ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
  ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
  ../../ofstd/include/dcmtk/ofstd/ofmap.h \
  ../../ofstd/include/dcmtk/ofstd/ofdate.h \
  ../../ofstd/include/dcmtk/ofstd/oftime.h \
index 45e43cda1b6fa0c5f2cd5f4330a499b4d94eb25a..2e2e23763fe8e22207ccb2912adac3aa6737039b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -110,7 +110,7 @@ void TrcTractographyResultsModule::resetRules()
   m_Rules->addRule(new IODRule(DCM_ContentTime, "1", "1", getName(), DcmIODTypes::IE_INSTANCE), OFTrue);
   m_Rules->addRule(new IODRule(DCM_ContentDate, "1", "1", getName(), DcmIODTypes::IE_INSTANCE), OFTrue);
   m_Rules->addRule(new IODRule(DCM_TrackSetSequence, "1-n", "1", getName(), DcmIODTypes::IE_INSTANCE), OFTrue);
-  m_Rules->addRule(new IODRule(DCM_ReferencedInstanceSequence, "1-n", "1", getName(), DcmIODTypes::IE_INSTANCE), OFTrue);
+  m_Rules->addRule(new IODRule(DCM_ReferencedInstanceSequence, "1-n", "1C", getName(), DcmIODTypes::IE_INSTANCE), OFTrue);
 }
 
 
@@ -193,13 +193,19 @@ OFCondition TrcTractographyResultsModule::addImageReference(const IODReference&
 
 OFCondition TrcTractographyResultsModule::check(const OFBool quiet)
 {
+  DCMTRACT_DEBUG("Checking Tractography Results Module");
+  DCMTRACT_DEBUG("Checking Content Identification");
   if (m_ContentIdentification.check().good())
   {
+    DCMTRACT_DEBUG("Content Identification is valid");
+    DCMTRACT_DEBUG("Checking Track Sets");
     if (m_TrackSets.size() > 0)
     {
+      DCMTRACT_DEBUG("Found " << m_TrackSets.size() << " Track Sets");
       OFVector<TrcTrackSet*>::iterator it = m_TrackSets.begin();
       while (it != m_TrackSets.end())
       {
+        DCMTRACT_DEBUG("Checking Track Set #" << (it - m_TrackSets.begin() + 1) << "/" << m_TrackSets.size());
         if ( (*it)->getNumberOfTracks() == 0)
         {
           DCMTRACT_ERROR("Track Set does not contain any tracks");
@@ -207,6 +213,7 @@ OFCondition TrcTractographyResultsModule::check(const OFBool quiet)
         }
         else
         {
+          DCMTRACT_DEBUG("Track Set contains " << (*it)->getNumberOfTracks() << " tracks, checking them");
           OFVector<TrcTrack*> tracks = (*it)->getTracks();
           OFVector<TrcTrack*>::iterator t = tracks.begin();
           while (t != tracks.end())
@@ -224,16 +231,23 @@ OFCondition TrcTractographyResultsModule::check(const OFBool quiet)
       return TRC_EC_NoSuchTrack;
     }
   }
+  else
+  {
+    DCMTRACT_ERROR("Content Identification is not valid");
+    return TRC_EC_InvalidContentIdentification;
+  }
   return checkColoring();
 }
 
 
 OFCondition TrcTractographyResultsModule::checkColoring()
 {
+  DCMTRACT_DEBUG("Checking Track Set coloring");
   size_t tsCount = 1;
   OFVector<TrcTrackSet*>::iterator ts = m_TrackSets.begin();
   while (ts != m_TrackSets.end())
   {
+    DCMTRACT_DEBUG("Checking Track Set coloring for Track Set #" << tsCount << "/" << m_TrackSets.size());
     // Collect statistics how much are colored
     OFVector<TrcTrack*>::const_iterator track = (*ts)->getTracks().begin();
     OFVector<TrcTrack*>::const_iterator last = (*ts)->getTracks().end();
index c01230e89840a19bcdc59f2f537091bee0422029..2091ee77f415bacc585a443e877d910e8d2b01bc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -141,16 +141,29 @@ OFCondition TrcTrackSet::read(DcmItem& source,
 
 OFCondition TrcTrackSet::write(DcmItem& destination)
 {
+  DCMTRACT_DEBUG("Writing Track Set");
   OFCondition result;
+  DCMTRACT_DEBUG("Writing Track Set Anatomical Type Code Sequence");
   DcmIODUtil::writeSingleItem(result, DCM_TrackSetAnatomicalTypeCodeSequence, m_Anatomy, getData(), getRules()->getByTag(DCM_TrackSetAnatomicalTypeCodeSequence));
+  DCMTRACT_DEBUG("Writing Diffusion Acquisition Code Sequence");
   DcmIODUtil::writeSingleItem(result, DCM_DiffusionAcquisitionCodeSequence, m_DiffusionAcquisitionCode, getData(), getRules()->getByTag(DCM_DiffusionAcquisitionCodeSequence));
+  DCMTRACT_DEBUG("Writing Diffusion Model Code Sequence");
   DcmIODUtil::writeSingleItem(result, DCM_DiffusionModelCodeSequence, m_DiffusionModelCode, getData(), getRules()->getByTag(DCM_DiffusionModelCodeSequence));
+  DCMTRACT_DEBUG("Writing Tracking Algorithm Identification Sequence");
   DcmIODUtil::writeSubSequence(result, DCM_TrackingAlgorithmIdentificationSequence, m_TrackingAlgorithmIdentification, getData(), getRules()->getByTag(DCM_TrackingAlgorithmIdentificationSequence));
+  DCMTRACT_DEBUG("Writing Track Statistics");
   writeTrackStatistics(result, getData());
+  DCMTRACT_DEBUG("Writing Track Set Statistics");
   writeTrackSetStatistics(result, getData());
+  DCMTRACT_DEBUG("Writing Track Set Measurements");
   writeMeasurements(result, getData());
+  DCMTRACT_DEBUG("Writing Track Set Tracks");
   writeTracks(result, getData());
-  if (result.good()) result = IODComponent::write(destination);
+  if (result.good())
+  {
+    DCMTRACT_DEBUG("Writing Track Set details");
+    result = IODComponent::write(destination);
+  }
   return result;
 }
 
index e062489185187acb877130f6e545f196148fb1b2..bea17882a41aea4db1b0f8778236c55c65f57c4a 100644 (file)
@@ -1,6 +1,6 @@
   /*
  *
- *  Copyright (C) 2016-2024, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
@@ -204,6 +204,10 @@ OFCondition TrcTractographyResults::write(DcmItem &dataset)
   // Common Instance Reference Module
   if (result.good()) result = DcmIODCommon::write(dataset);
 
+  // Write Tractography Results Series attributes which is not covered by a specific class
+  // but part of "this" class
+  if (result.good()) result = IODComponent::write(*getData(), *getRules(), dataset, "TractographyResultsSeries", getValueCheckOnWrite());
+
   return result;
 }
 
index d2fbe94dfcd2b891159fc93a9ce53ba1e73556e5..d20fe5780749eb5a3121c8c22384243b6819b60d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2016, Open Connections GmbH
+ *  Copyright (C) 2016-2025, Open Connections GmbH
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation are maintained by
 
 OFLogger DCM_dcmtractLogger = OFLog::getLogger("dcmtk.dcmtract");
 
-makeOFConditionConst(TRC_EC_InvalidPointCoordinatesData, OFM_dcmtract, 1, OF_error, "Invalid data in Track's Point Coordinates Data element");
-makeOFConditionConst(TRC_EC_InvalidColorInformation,     OFM_dcmtract, 2, OF_error, "Invalid color information for Track or Track Set");
-makeOFConditionConst(TRC_EC_NoSuchTrack,                 OFM_dcmtract, 3, OF_error, "No such Track in Track Set");
-makeOFConditionConst(TRC_EC_NoSuchMeasurement,           OFM_dcmtract, 4, OF_error, "No such Measurement in Track Set");
-makeOFConditionConst(TRC_EC_MeasurementDataMissing,      OFM_dcmtract, 5, OF_error, "Measurement misses data for one or more tracks");
-makeOFConditionConst(TRC_EC_InvalidStatisticData,        OFM_dcmtract, 6, OF_error, "Statistic data is invalid");
-makeOFConditionConst(TRC_EC_InvalidTrackData,            OFM_dcmtract, 7, OF_error, "Track data is invalid");
+makeOFConditionConst(TRC_EC_InvalidPointCoordinatesData,  OFM_dcmtract, 1, OF_error, "Invalid data in Track's Point Coordinates Data element");
+makeOFConditionConst(TRC_EC_InvalidColorInformation,      OFM_dcmtract, 2, OF_error, "Invalid color information for Track or Track Set");
+makeOFConditionConst(TRC_EC_NoSuchTrack,                  OFM_dcmtract, 3, OF_error, "No such Track in Track Set");
+makeOFConditionConst(TRC_EC_NoSuchMeasurement,            OFM_dcmtract, 4, OF_error, "No such Measurement in Track Set");
+makeOFConditionConst(TRC_EC_MeasurementDataMissing,       OFM_dcmtract, 5, OF_error, "Measurement misses data for one or more tracks");
+makeOFConditionConst(TRC_EC_InvalidStatisticData,         OFM_dcmtract, 6, OF_error, "Statistic data is invalid");
+makeOFConditionConst(TRC_EC_InvalidTrackData,             OFM_dcmtract, 7, OF_error, "Track data is invalid");
+makeOFConditionConst(TRC_EC_InvalidContentIdentification, OFM_dcmtract, 8, OF_error, "Invalid Content Identification for Tractography Results object");
diff --git a/dcmtract/tests/CMakeLists.txt b/dcmtract/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..badf82a
--- /dev/null
@@ -0,0 +1,11 @@
+# declare executables
+DCMTK_ADD_TEST_EXECUTABLE(dcmtract_tests
+  tcreate.cc
+  tests.cc
+)
+
+# make sure executables are linked to the corresponding libraries
+DCMTK_TARGET_LINK_MODULES(dcmtract_tests dcmtract)
+
+# This macro parses tests.cc and registers all tests
+DCMTK_ADD_TESTS(dcmtract)
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ff6a3ca63f76e1fee1ee5a3eefaab248f397c8a2 100644 (file)
@@ -0,0 +1,159 @@
+tcreate.o: tcreate.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmtract/trctractographyresults.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsconstexp.def \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../include/dcmtk/dcmtract/trctrackset.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodutil.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../include/dcmtk/dcmtract/trctypes.h ../include/dcmtk/dcmtract/trcdef.h \
+ ../include/dcmtk/dcmtract/trcmodtractresults.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../ofstd/include/dcmtk/ofstd/oftempf.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h
+tests.o: tests.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h
index 644480a637c2914c55aebd15903f5ec3d222a334..cbac4cdfd106db2b2391a5c4a71701f44e49e216 100644 (file)
@@ -5,25 +5,58 @@
 @SET_MAKE@
 
 SHELL = /bin/sh
+VPATH = @srcdir@:@top_srcdir@/include:@top_srcdir@/@configdir@/include
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 configdir = @top_srcdir@/@configdir@
 
 include $(configdir)/@common_makefile@
 
+oficonvdir = $(top_srcdir)/../oficonv
+ofstddir = $(top_srcdir)/../ofstd
+oflogdir = $(top_srcdir)/../oflog
+dcmdatadir = $(top_srcdir)/../dcmdata
+dcmioddir = $(top_srcdir)/../dcmiod
+dcmfgdir = $(top_srcdir)/../dcmfg
 
-all:
+LOCALINCLUDES = -I$(top_srcdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \
+       -I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include
+LIBDIRS = -L$(top_srcdir)/libsrc -L$(oficonvdir)/libsrc -L$(ofstddir)/libsrc \
+       -L$(oflogdir)/libsrc -L$(dcmdatadir)/libsrc -L$(dcmioddir)/libsrc \
+       -L$(dcmfgdir)/libsrc
+LOCALLIBS = -ldcmtract -ldcmfg -ldcmiod -ldcmdata -loflog -lofstd -loficonv \
+       $(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS)
 
-check:
+test_objs = tcreate.o tests.o
 
-check-exhaustive:
+objs = $(test_objs)
+progs = tests
+
+
+all: $(progs)
+
+tests: $(test_objs)
+       $(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $(test_objs) $(LOCALLIBS) $(LIBS)
+
+
+check: tests
+       DCMDICTPATH=../../dcmdata/data/dicom.dic ./tests
+
+check-exhaustive: tests
+       DCMDICTPATH=../../dcmdata/data/dicom.dic ./tests -x
+
+
+install: all
 
-install:
 
 clean:
-       rm -f $(TRASH)
+       rm -f $(objs) $(progs) $(TRASH)
 
 distclean:
-       rm -f $(DISTTRASH)
+       rm -f $(objs) $(progs) $(DISTTRASH)
+
 
 dependencies:
+       $(CXX) -MM $(defines) $(includes) $(CPPFLAGS) $(CXXFLAGS) *.cc  > $(DEP)
+
+include $(DEP)
diff --git a/dcmtract/tests/tcreate.cc b/dcmtract/tests/tcreate.cc
new file mode 100644 (file)
index 0000000..6ec7a15
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmtract
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: Tests that check for pixel data overflow conditions
+ *
+ */
+
+
+#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
+
+#include "dcmtk/dcmtract/trctractographyresults.h"
+#include "dcmtk/dcmdata/dcfilefo.h"
+#include "dcmtk/ofstd/oftest.h"
+#include "dcmtk/ofstd/oftempf.h"
+#include "dcmtk/dcmdata/dcdict.h"
+
+static OFString EXPECTED_DUMP;
+
+static TrcTractographyResults *create();
+static void setGenericValues(TrcTractographyResults *ct);
+
+
+OFTEST(dcmtract_create)
+{
+    /* make sure data dictionary is loaded */
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+        OFCHECK(dcmDataDict.isDictionaryLoaded());
+    }
+
+    // Creation
+    TrcTractographyResults* tract(create());
+    OFCHECK(tract != OFnullptr);
+
+
+    setGenericValues(tract);
+
+    // Write to dataset and compare its dump with expected result
+    DcmFileFormat dcmff;
+
+    // We just use this to create a temporary file name
+    OFTempFile tf(O_RDWR, "", "dcmtract_create", ".dcm");
+    OFCondition result;
+    result = tract->saveFile(tf.getFilename(), EXS_LittleEndianExplicit);
+    OFCHECK_MSG(result == EC_Normal, result.text());
+    delete tract; // delete tractography results object
+}
+
+static TrcTractographyResults *create()
+{
+    IODEnhGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
+    TrcTractographyResults *tract = NULL;
+    OFCondition result;
+    result = TrcTractographyResults::create(ContentIdentificationMacro("1", "LABEL", "Description", "Open Connections"),
+                                            "20250527",
+                                            "103100",
+                                            eq,
+                                            IODReferences(),
+                                            tract);
+
+    OFCHECK(result.good());
+    OFCHECK(tract != OFnullptr);
+    return tract;
+}
+
+
+static void setGenericValues(TrcTractographyResults *tract)
+{
+    if (!tract)
+        return;
+    OFCHECK(tract->getPatient().setPatientName("Bond^James").good());
+    OFCHECK(tract->getPatient().setPatientID("007").good());
+    OFCHECK(tract->getPatient().setPatientBirthDate("19771007").good());
+    OFCHECK(tract->getStudy().setStudyDate("20250101").good());
+    OFCHECK(tract->getStudy().setStudyTime("120000").good());
+    OFCHECK(tract->getStudy().setStudyID("1").good());
+    OFCHECK(tract->getPatientStudy().setPatientAge("047Y").good());
+    OFCHECK(tract->getSeries().setSeriesDescription("Test Description").good());
+    OFCHECK(tract->getSeries().setSeriesNumber("1").good());
+
+    // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
+    // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
+    // so that they are not overwritten with new, automatically created values later.
+    OFCHECK(tract->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
+    OFCHECK(tract->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
+    OFCHECK(tract->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
+    OFCHECK(tract->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
+
+    // Create trackset
+    CodeWithModifiers trackSetAnatomy("3", "1");
+    trackSetAnatomy.set("12738006", "SCT", "Brain");
+    // Create algo identification macro
+    AlgorithmIdentificationMacro algo;
+    algo.getAlgorithmFamilyCode().set("4711", "99OC", "Dummy Tracking");
+    algo.setAlgorithmName("Deterministic Tracking");
+    algo.setAlgorithmVersion("1.0");
+    algo.setAlgorithmParameters("Parameter1=Value1\\Parameter2=Value2");
+    algo.setAlgorithmSource("Open Connections");
+
+    TrcTrackSet* tractSet = NULL;
+
+    // Add trackset to tractography results
+    OFCondition result = tract->addTrackSet("TRACK_SET_LABEL", "Track Set Description",
+                                trackSetAnatomy,
+                                CodeSequenceMacro("113231", "DCM", "Single Tensor"),
+                                algo, tractSet);
+
+    OFCHECK(result.good());
+    OFCHECK(tractSet != OFnullptr);
+
+    // Add tracks to trackset
+    Float32 points[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f };
+    Uint16 colors[] = { 0, 0, 0 };
+    TrcTrack* track = NULL;
+    result = tractSet->addTrack(points, 2, colors, 1, track);
+    OFCHECK(result.good());
+    OFCHECK(track != OFnullptr);
+}
diff --git a/dcmtract/tests/tests.cc b/dcmtract/tests/tests.cc
new file mode 100644 (file)
index 0000000..68fc25c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  dcmtract
+ *
+ *  Author:  Michael Onken
+ *
+ *  Purpose: main test program
+ *
+ */
+
+#include "dcmtk/config/osconfig.h"
+
+#include "dcmtk/ofstd/oftest.h"
+
+OFTEST_REGISTER(dcmtract_create);
+
+OFTEST_MAIN("dcmtract")
index 45f0fdd3f4be869f5a315651ca0f5d2afda9c4db..9131b13a09bebb451434e0ba12ba5b186e12c495 100644 (file)
@@ -5,4 +5,4 @@ include_directories("${dcmtls_SOURCE_DIR}/include")
 DCMTK_ADD_EXECUTABLE(wlmscpfs wlmscpfs.cc wlcefs.cc)
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(wlmscpfs dcmwlm dcmnet dcmtls dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(wlmscpfs dcmwlm)
index 345eb6444dab280867c3759b7a105733ed1608be..685a44123f56bf74d6b1760da9ae5acb34d3c231 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2024, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -136,6 +136,11 @@ WlmConsoleEngineFileSystem::WlmConsoleEngineFileSystem( int argc, char *argv[],
       cmd->addOption("--no-sq-expansion",     "-nse",    "disable expansion of empty sequences in C-FIND\nrequest messages");
 
   cmd->addGroup("network options:");
+    cmd->addSubGroup("IP protocol version:");
+      cmd->addOption("--ipv4",                "-i4",     "use IPv4 only (default)");
+      cmd->addOption("--ipv6",                "-i6",     "use IPv6 only");
+      cmd->addOption("--ip-auto",             "-i0",     "use IPv6/IPv4 dual stack");
+
     cmd->addSubGroup("preferred network transfer syntaxes:");
       cmd->addOption("--prefer-uncompr",      "+x=",     "prefer explicit VR local byte order (default)");
       cmd->addOption("--prefer-little",       "+xe",     "prefer explicit VR little endian TS");
@@ -255,6 +260,14 @@ WlmConsoleEngineFileSystem::WlmConsoleEngineFileSystem( int argc, char *argv[],
     if( cmd->findOption("--no-sq-expansion") ) opt_noSequenceExpansion = OFTrue;
 
     // network options
+
+    // set the IP protocol version
+    cmd->beginOptionBlock();
+    if (cmd->findOption("--ipv4")) dcmIncomingProtocolFamily.set(ASC_AF_INET);
+    if (cmd->findOption("--ipv6")) dcmIncomingProtocolFamily.set(ASC_AF_INET6);
+    if (cmd->findOption("--ip-auto")) dcmIncomingProtocolFamily.set(ASC_AF_UNSPEC);
+    cmd->endOptionBlock();
+
     cmd->beginOptionBlock();
     if( cmd->findOption("--prefer-uncompr") ) opt_networkTransferSyntax = EXS_Unknown;
     if( cmd->findOption("--prefer-little") ) opt_networkTransferSyntax = EXS_LittleEndianExplicit;
index a0c096b358e3f0375ab967566a2a5d8ce58bf637..02d87b075d73b5d8cad246ae0c433266de1965ad 100644 (file)
@@ -108,6 +108,17 @@ other processing options:
 
 \subsection wlmscpfs_network_options network options
 \verbatim
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 preferred network transfer syntaxes:
 
   +x=   --prefer-uncompr
@@ -380,7 +391,7 @@ As return keys the following attributes are currently supported by \b wlmscpfs:
 (0010,1080) MilitaryRank
 (0010,2000) MedicalAlerts
 (0010,2110) ContrastAllergies
-(0010,2160) EthnicGroup
+(0010,2160) EthnicGroup (retired)
 (0010,21a0) SmokingStatus
 (0010,21b0) AdditionalPatientHistory
 (0010,21c0) PregnancyStatus
@@ -515,6 +526,6 @@ It is an error if no data dictionary can be loaded.
 
 \section wlmscpfs_copyright COPYRIGHT
 
-Copyright (C) 1996-2024 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
+Copyright (C) 1996-2025 by OFFIS e.V., Escherweg 2, 26121 Oldenburg, Germany.
 
 */
index 4a076bcb34cf14aa030e5664ccb16717cf28de9f..7284d92da71a8ee0d2950ee5a668aafee03d5c48 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2023, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -211,7 +211,7 @@ class DCMTK_DCMWLM_EXPORT WlmDataSource
        *    DCM_AdmittingDiagnosesDescription                     (0008,1080)  LO  O  3  (from the Visit Admission Module)
        *    DCM_RETIRED_OtherPatientIDs                           (0010,1000)  LO  O  3  (from the Patient Identification Module)
        *    DCM_PatientSize                                       (0010,1020)  DS  O  3  (from the Patient Demographic Module)
-       *    DCM_EthnicGroup                                       (0010,2160)  SH  O  3  (from the Patient Demographic Module)
+       *    DCM_RETIRED_EthnicGroup                               (0010,2160)  SH  O  3  (from the Patient Demographic Module)
        *    DCM_PatientComments                                   (0010,4000)  LT  O  3  (from the Patient Demographic Module)
        *    DCM_AdditionalPatientHistory                          (0010,21b0)  LT  O  3  (from the Patient Medical Module)
        *    DCM_LastMenstrualDate                                 (0010,21d0)  DA  O  3  (from the Patient Medical Module)
index 635af2fb69609882a0ce9eb0602508355b942b26..0c4ac472f270afb239c44d59943edac11cb55eb0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2023, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -1071,7 +1071,7 @@ OFBool WlmDataSource::IsSupportedReturnKeyAttribute( DcmElement *element, DcmSeq
 //                   DCM_AdmittingDiagnosesDescription                     (0008,1080)  LO  O  3  (from the Visit Admission Module)
 //                   DCM_RETIRED_OtherPatientIDs                           (0010,1000)  LO  O  3  (from the Patient Identification Module)
 //                   DCM_PatientSize                                       (0010,1020)  DS  O  3  (from the Patient Demographic Module)
-//                   DCM_EthnicGroup                                       (0010,2160)  SH  O  3  (from the Patient Demographic Module)
+//                   DCM_RETIRED_EthnicGroup                               (0010,2160)  SH  O  3  (from the Patient Demographic Module)
 //                   DCM_PatientComments                                   (0010,4000)  LT  O  3  (from the Patient Demographic Module)
 //                   DCM_AdditionalPatientHistory                          (0010,21b0)  LT  O  3  (from the Patient Medical Module)
 //                   DCM_LastMenstrualDate                                 (0010,21d0)  DA  O  3  (from the Patient Medical Module)
@@ -1195,7 +1195,7 @@ OFBool WlmDataSource::IsSupportedReturnKeyAttribute( DcmElement *element, DcmSeq
         elementKey == DCM_AdmittingDiagnosesDescription                     ||
         elementKey == DCM_RETIRED_OtherPatientIDs                           ||
         elementKey == DCM_PatientSize                                       ||
-        elementKey == DCM_EthnicGroup                                       ||
+        elementKey == DCM_RETIRED_EthnicGroup                               ||
         elementKey == DCM_PatientComments                                   ||
         elementKey == DCM_AdditionalPatientHistory                          ||
         elementKey == DCM_LastMenstrualDate                                 ||
index d821bb79c00f0fefc0e7d0fa923b82e2b0f79ecb..ee83d7b0748d55807fcb8323c3e44a8c51255eb6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1996-2023, OFFIS e.V.
+ *  Copyright (C) 1996-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -23,9 +23,7 @@
 
 #include "dcmtk/config/osconfig.h"  // specific configuration for operating system
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>     // for O_RDWR
-#endif
 END_EXTERN_C
 #include "dcmtk/ofstd/oftypes.h"
 #include "dcmtk/ofstd/ofstd.h"
index a92cf91d21c68381599bf041e6df9f733e6ca43e..458840d61366a6d9ea9253962449a4507ac1f099 100644 (file)
@@ -2,4 +2,4 @@
 DCMTK_ADD_TEST_EXECUTABLE(wltest wltest.cc)
 
 # make sure executables are linked to the corresponding libraries
-DCMTK_TARGET_LINK_MODULES(wltest dcmwlm dcmnet dcmtls dcmdata oflog ofstd)
+DCMTK_TARGET_LINK_MODULES(wltest dcmwlm dcmtls)
diff --git a/docs/ANNOUNCE.369 b/docs/ANNOUNCE.369
new file mode 100644 (file)
index 0000000..646567c
--- /dev/null
@@ -0,0 +1,168 @@
+ANNOUNCEMENT
+
+Version 3.6.9 of the OFFIS DCMTK (DICOM toolkit) software is now available for
+public release.  This release includes the following main changes over the
+previous version 3.6.8:
+
+- DCMTK 3.6.9 builds correctly on older and up-to-date versions of GNU gcc
+  (9.5.0 to 14.2.0), Clang (14.0.6 to 18.1.8), Apple Clang (14.0.3 to 15.0.0),
+  and Microsoft Visual Studio (2017 to 2022).
+
+- Tested with the following operating systems/environments:
+  - Android on arm64
+  - FreeBSD on x86_64
+  - Linux on x86_64 and x86
+  - MacOS X on x86_64 and arm64
+  - NetBSD on x86_64
+  - OpenBSD on x86_64
+  - OpenIndiana on x86_64
+  - Windows (including MinGW) on x86_64 and x86
+
+  For a complete list of tested systems and compilers, see the INSTALL file.
+
+- Updated DICOM data dictionary, list of SOP classes, well-known frame of
+  references, transfer syntaxes, code definitions, supported context group
+  classes, and directory record types for DICOM standard release 2024e:
+
+  - This also includes the latest attributes and SOP classes for the DICONDE
+    standard, e.g. for thermography images (based on ASTM E3440).
+
+  - Also updated the DICOMDIR generation code and tools accordingly.
+
+
+- The new JPEG XL and HTJ2K transfer syntaxes as well as the encapsulated
+  uncompressed transfer syntax are now supported for reading and writing, i.e.
+  for both files and network transfer.  However, encoders or decoders have not
+  been implemented yet.
+
+- Added new command line tool dcm2img that unifies and replaces the tools
+  dcm2pnm, dcmj2pnm and dcml2pnm, and adds support for JPEG-LS as an export
+  format for image files.  The command line options are identical to the older
+  tools, so that dcm2img can serve as a drop-in replacement:
+
+  - By default, the new command line tool determines the output format
+    automatically based on the extension of the output filename.
+
+  - The deprecated command line tools were replaced by stubs, which are provided
+    for the user's convenience, but will be removed with a future release.
+
+- Added new command line tool dcm2cda that extracts a CDA document from a DICOM
+  Encapsulated CDA Storage SOP Instance and stores it in a separate file.
+
+- Replaced command line tool dcmgpdir by a stub that calls the more
+  comprehensive command line tool dcmmkdir.
+
+- Further enhanced and updated DICOM Structured Reporting (SR) module "dcmsr":
+
+  - Added support for the new Waveform Annotation SR IOD (introduced with
+    Supplement 239).
+
+  - Made URL prefix for hyperlinks to composite objects configurable.
+
+  - Updated code definitions and supported context group classes (see above).
+
+  - Fixed issue with various IOD constraint checkers (see CP-2084).
+
+- Added IPv6 support to DCMTK's association requestors.  All DCMTK "client"
+  applications that only request outgoing DICOM network associations can now
+  explicitly select the protocol version to be used.  IPv6 support is not yet
+  implemented for association acceptors ("server" applications).
+
+- Various TLS enhancements:
+
+  - Added TLS support to the command line tools dcmqrscp and getscu.
+
+  - Added support for the Modified BCP 195 RFC 8996 TLS Profile.
+
+  - Added new command line option --list-profiles to all TLS-enabled tools.
+    This option prints a list of the TLS Secure Transport Connection Profiles
+    supported.
+
+  - Removed support for OpenSSL 1.0.2 and 1.1.0 and added support for OpenSSL
+    3.1.0 to 3.4.0.
+
+- Extended central DCMTK data structure where all SOP Classes are defined with
+  their associated properties, e.g. type and sub-type.
+
+- Largely enhanced basic transfer syntax class DcmXfer, e.g. to distinguish
+  more clearly between encapsulation and compression.  Please note that some of
+  the old methods have been deprecated and will be removed in a future release.
+
+- Enhanced performance of OFGlobal class, especially when used in applications
+  with many threads that read global objects of this class concurrently.
+
+- New, fully standards compliant implementations of OFStandard::atof() and
+  OFStandard::ftoa(), DCMTK's locale independent conversion routines between
+  floating point numbers and text.
+
+- Removed support for ICU-based character set conversion.  Since the oficonv
+  module in DCMTK supports all DICOM Specific Character Sets, the ICU support,
+  which was never complete, has been removed.
+
+- DCMTK now requires compilers to provide conformance to C++98 and supports
+  compilation with newer C++ versions up to C++20, which can be enabled via
+  CMake's CMAKE_CXX_STANDARD variable.  By default, C++11 is now enabled on
+  compilers that support this.
+
+- CMake-related enhancements and other changes:
+
+  - The configure process now respects CMake's CMAKE_CROSSCOMPILING_EMULATOR
+    variable.
+
+  - Exposed the CMAKE_DEBUG_POSTFIX variable to the user.  There are extra
+    options to also enable the postfix for Windows DLLs as well as executables.
+
+- Many configure tests related to outdated compilers or libraries were removed,
+  thus significantly speeding up the configuration process.
+
+- Fixed binary segmentations with certain dimensions (some cases where number
+  of total bits per frame is not divisible by 8) that were broken when being
+  serialized into a dataset.
+
+- Fixed various other issues that occurred after the official 3.6.8 release,
+  and further improved the performance.  See CHANGES file for details.
+
+Many people have contributed to this new release of DCMTK, appearing here in
+alphabetical order.  Thank you very much for your support!
+
+  Christian Wetzel <wetzel@phoenix-pacs.de>
+  David Gobbi <david.gobbi@gmail.com>
+  David Seifert <soap@gentoo.org>
+  Giulio Simonetti <giulio.simonetti@datamind.biz>
+  Helmut Steiner <helmut@shl.at>
+  Jean Pierre Bassenge <jp.bassenge@fiagon.com>
+  Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
+  Jesper Alf Dam <Jesper.Dam@mi.medical.canon>
+  Kevin Leonardic <kevin@leonardic.de>
+  Marcel Pham <Marcel.Pham@examion.com>
+  Mario Galijot <mario@salaourn.com>
+  Markus Sabin <Markus.Sabin@soft-gate.de>
+  Martin Zeiser of the Cisco Talos team <vulndiscovery@external.cisco.com>
+  Mathieu Malaterre <mathieu.malaterre@gmail.com>
+  Matt McCormick <matt.mccormick@kitware.com>
+  Melanie Michels <melanie.michels@snkeos.com>
+  Nils Bars <nils.bars@rub.de>
+  Peter Klotz <peter.klotz@siemens-healthineers.com>
+  Phileas Lebada <phileas@contextflow.com>
+  Piotr Batko <Piotr.Batko@gehealthcare.com>
+  Sam James <sam@gentoo.org>
+  Sobhita Mercy <sobhitamercy@gmail.com>
+  Yoshinaga Kosuke <kosuke.yoshinaga@goodmankk.com>
+
+  DCMTK forum users "andreasb", "Fabian Guenther", "nbeck", "Oleh", "saltcreek"
+
+  GitHub users "akaraivanov", "bananabr", "khangthk", "luissantosHCIT",
+    "malaterre", "mrbean-bremen", "percontation", "thewtex"
+
+Members of the DCMTK Team who have worked on this release are:
+
+  Joerg Riesmeier <dicom@jriesmeier.com>
+  Marco Eichelberg <eichelberg@offis.de>
+  Michael Onken <onken@open-connections.de>
+  Tingyan Xu <tingyan.xu@offis.de>
+
+The DCMTK software can be downloaded via:
+
+  https://dicom.offis.de/dcmtk or https://www.dcmtk.org/
+
+OFFIS e.V., Oldenburg, Germany, 2024-12-10
diff --git a/docs/CHANGES.370 b/docs/CHANGES.370
new file mode 100644 (file)
index 0000000..22c33f9
--- /dev/null
@@ -0,0 +1,3027 @@
+
+Release 3.7.0 (Public Minor Release - 2025-12-15)
+
+**** Changes from 2025.12.15 (eichelberg)
+
+- Created CHANGES.370 for DCMTK release 3.7.0:
+  CHANGES.370 contains the Git commit history since DCMTK release 3.6.9.
+  Added:   docs/CHANGES.370
+
+- Updated man pages for DCMTK release 3.7.0.
+  Added:   doxygen/manpages/man1/dcmdecap.1
+           doxygen/manpages/man1/dcmencap.1
+           doxygen/manpages/man1/json2dcm.1
+  Affects: doxygen/manpages/man1/cda2dcm.1
+           doxygen/manpages/man1/dcm2cda.1
+           doxygen/manpages/man1/dcm2img.1
+           doxygen/manpages/man1/dcm2json.1
+           doxygen/manpages/man1/dcm2pdf.1
+           doxygen/manpages/man1/dcm2pnm.1
+           doxygen/manpages/man1/dcm2xml.1
+           doxygen/manpages/man1/dcmcjpeg.1
+           doxygen/manpages/man1/dcmcjpls.1
+           doxygen/manpages/man1/dcmconv.1
+           doxygen/manpages/man1/dcmcrle.1
+           doxygen/manpages/man1/dcmdjpeg.1
+           doxygen/manpages/man1/dcmdjpls.1
+           doxygen/manpages/man1/dcmdrle.1
+           doxygen/manpages/man1/dcmdspfn.1
+           doxygen/manpages/man1/dcmdump.1
+           doxygen/manpages/man1/dcmftest.1
+           doxygen/manpages/man1/dcmgpdir.1
+           doxygen/manpages/man1/dcmicmp.1
+           doxygen/manpages/man1/dcmj2pnm.1
+           doxygen/manpages/man1/dcml2pnm.1
+           doxygen/manpages/man1/dcmmkcrv.1
+           doxygen/manpages/man1/dcmmkdir.1
+           doxygen/manpages/man1/dcmmklut.1
+           doxygen/manpages/man1/dcmodify.1
+           doxygen/manpages/man1/dcmp2pgm.1
+           doxygen/manpages/man1/dcmprscp.1
+           doxygen/manpages/man1/dcmprscu.1
+           doxygen/manpages/man1/dcmpschk.1
+           doxygen/manpages/man1/dcmpsmk.1
+           doxygen/manpages/man1/dcmpsprt.1
+           doxygen/manpages/man1/dcmpsrcv.1
+           doxygen/manpages/man1/dcmpssnd.1
+           doxygen/manpages/man1/dcmqridx.1
+           doxygen/manpages/man1/dcmqrscp.1
+           doxygen/manpages/man1/dcmqrti.1
+           doxygen/manpages/man1/dcmquant.1
+           doxygen/manpages/man1/dcmrecv.1
+           doxygen/manpages/man1/dcmscale.1
+           doxygen/manpages/man1/dcmsend.1
+           doxygen/manpages/man1/dcmsign.1
+           doxygen/manpages/man1/dcod2lum.1
+           doxygen/manpages/man1/dconvlum.1
+           doxygen/manpages/man1/drtdump.1
+           doxygen/manpages/man1/dsr2html.1
+           doxygen/manpages/man1/dsr2xml.1
+           doxygen/manpages/man1/dsrdump.1
+           doxygen/manpages/man1/dump2dcm.1
+           doxygen/manpages/man1/echoscu.1
+           doxygen/manpages/man1/findscu.1
+           doxygen/manpages/man1/getscu.1
+           doxygen/manpages/man1/img2dcm.1
+           doxygen/manpages/man1/mkcsmapper.1
+           doxygen/manpages/man1/mkesdb.1
+           doxygen/manpages/man1/movescu.1
+           doxygen/manpages/man1/pdf2dcm.1
+           doxygen/manpages/man1/stl2dcm.1
+           doxygen/manpages/man1/storescp.1
+           doxygen/manpages/man1/storescu.1
+           doxygen/manpages/man1/termscu.1
+           doxygen/manpages/man1/wlmscpfs.1
+           doxygen/manpages/man1/xml2dcm.1
+           doxygen/manpages/man1/xml2dsr.1
+
+- Updated version information for DCMTK release 3.7.0.
+  Affects: CMake/dcmtkPrepare.cmake
+
+- Updated copyright date.
+  Affects: dcmdata/docs/dcm2xml.man
+           dcmdata/docs/dcmconv.man
+           dcmdata/docs/dcmcrle.man
+           dcmdata/docs/dcmdrle.man
+           dcmdata/docs/dcmdump.man
+           dcmdata/docs/dcmftest.man
+           dcmdata/docs/dcmgpdir.man
+           dcmdata/docs/dcmodify.man
+           dcmdata/docs/dump2dcm.man
+           dcmdata/docs/img2dcm.man
+           dcmdata/docs/xml2dcm.man
+           dcmimage/docs/dcm2pnm.man
+           dcmimage/docs/dcmicmp.man
+           dcmimage/docs/dcmquant.man
+           dcmimage/docs/dcmscale.man
+           dcmimgle/docs/dcmdspfn.man
+           dcmimgle/docs/dcod2lum.man
+           dcmimgle/docs/dconvlum.man
+           dcmjpeg/docs/dcmcjpeg.man
+           dcmjpeg/docs/dcmj2pnm.man
+           dcmjpeg/docs/dcmmkdir.man
+           dcmjpls/docs/dcmcjpls.man
+           dcmjpls/docs/dcmdjpls.man
+           dcmjpls/docs/dcml2pnm.man
+           dcmnet/docs/dcmsend.man
+           dcmnet/docs/findscu.man
+           dcmnet/docs/storescu.man
+           dcmnet/docs/termscu.man
+           dcmpstat/docs/dcmmkcrv.man
+           dcmpstat/docs/dcmmklut.man
+           dcmpstat/docs/dcmp2pgm.man
+           dcmpstat/docs/dcmpschk.man
+           dcmpstat/docs/dcmpsmk.man
+           dcmpstat/docs/dcmpsprt.man
+           dcmpstat/docs/dcmpsrcv.man
+           dcmpstat/docs/dcmpssnd.man
+           dcmqrdb/docs/dcmqridx.man
+           dcmqrdb/docs/dcmqrti.man
+           dcmrt/docs/drtdump.man
+           dcmsign/docs/dcmsign.man
+
+- Updated autoconf files for upcoming release.
+  Affects: VERSION
+           config/configure
+           config/configure.in
+           config/confmod
+
+- Updated URL for Windows support libs.
+  Affects: .github/workflows/cmake-win.yml
+
+- Updated documentation for upcoming release.
+  Affects: ANNOUNCE
+           CREDITS
+           INSTALL
+
+**** Changes from 2025.12.12 (eichelberg)
+
+- Fixed warnings reported on Android.
+  Affects: dcmpstat/apps/dcmpssnd.cc
+           dcmqrdb/libsrc/dcmqrcbg.cc
+           dcmqrdb/libsrc/dcmqrcbm.cc
+           dcmqrdb/libsrc/dcmqrdbi.cc
+           dcmqrdb/libsrc/dcmqrsrv.cc
+           dcmqrdb/libsrc/dcmqrtis.cc
+           ofstd/include/dcmtk/ofstd/ofstd.h
+           ofstd/libsrc/offilsys.cc
+
+- Fixed documentation:
+  Fixed an incorrect API documentation.
+  Thanks to Matt Hancock <mhancock@innolitics.com> for the report.
+  Affects: dcmnet/include/dcmtk/dcmnet/scp.h
+           dcmnet/include/dcmtk/dcmnet/scpcfg.h
+
+**** Changes from 2025.12.11 (goldhammer)
+
+- Updated CMake files for Android API 35:
+  Updated the CMake toolchain for Android API level 35 and Android NDK R27.
+  Affects: CMake/CTest/CTestCustomAndroid.cmake.in
+           CMake/CTest/dcmtkCTestRunAndroid.cmake.in
+           CMake/dcmtkMacros.cmake
+           CMake/dcmtkUseAndroidSDK.cmake
+           CMakeLists.txt
+
+**** Changes from 2025.12.09 (riesmeier)
+
+- Avoid wrong warning message on private pixel data:
+  Made sure that a warning message on compressed private pixel data is
+  only reported if the element length is really undefined.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the
+  original report.
+  Affects: dcmdata/libsrc/dcitem.cc
+
+**** Changes from 2025.12.08 (riesmeier)
+
+- Fixed issue when charset conversion is disabled:
+  Fixed compilation error when character set conversion has been disabled
+  during configuration process.
+  Affects: dcmsr/apps/dsrdump.cc
+
+**** Changes from 2025.12.02 (eichelberg)
+
+- Fixed bug in handling of odd-length data elements:
+  When a dataset containing an illegal odd-length attribute with a text VR
+  was read from file or received over a network connection, then accessing
+  the value of that attribute with DcmElement::getString() may return a
+  pointer to a string that was not properly null terminated. Using C string
+  functions such as strlen() or strcpy() on that string then lead to a read
+  beyond the end of a string, causing a segmentation fault.
+  Thanks to Zou Dikai <zoudikai@outlook.com> for the bug report and POC.
+  This closes DCMTK issue #1184.
+  Affects: dcmdata/libsrc/dcbytstr.cc
+
+**** Changes from 2025.11.28 (riesmeier)
+
+- Updated information on latest CMake version:
+  Changed latest CMake version that was tested to 4.2.0.
+  Affects: CMakeLists.txt
+
+**** Changes from 2025.11.28 (eichelberg)
+
+- Fixed two possible segfaults in dcmqrscp:
+  Fixed two places where invalid messages may trigger a segmentation fault
+  due to a NULL pointer being de-referenced.
+  Thanks to 邹 迪凯 <zoudikai@outlook.com> for the bug report and proof-of-concept.
+  Affects: dcmqrdb/libsrc/dcmqrdbi.cc
+
+**** Changes from 2025.11.27 (eichelberg)
+
+- Fixed errors when compiling with C++98.
+  Affects: dcmseg/include/dcmtk/dcmseg/overlaputil.h
+           dcmseg/libsrc/segdoc.cc
+
+**** Changes from 2025.11.26 (onken)
+
+- Fix compiler warning on unreachable code.
+  Affects: dcmseg/libsrc/overlaputil.cc
+
+**** Changes from 2025.11.26 (eichelberg)
+
+- Fixed strlcpy related issue in oficonv:
+  Replaced two calls of strlcpy with strncpy in places where the source
+  string is not guaranteed to be always null terminated, which strlcpy requires.
+  Thanks to DCMTK forum user "saltcreek" for the original report.
+  Affects: oficonv/libsrc/citrus_mapper.c
+
+**** Changes from 2025.11.25 (onken)
+
+- Avoid compiler warning for VS 2022 on Windows 10.
+  Affects: dcmseg/libsrc/overlaputil.cc
+
+**** Changes from 2025.11.25 (riesmeier)
+
+- Fixed wrong use of ESC in "LO" and "SH" test case:
+  Thanks to GitHub user "mrbean-bremen" for the original report and
+  proposed patch (see PR #124).
+  Affects: dcmdata/tests/tchval.cc
+
+- Updated copyright date.
+  Affects: COPYRIGHT
+
+**** Changes from 2025.11.25 (onken)
+
+- Fix compiler warnings/errors from 74bba5.
+  Affects: dcmfg/include/dcmtk/dcmfg/framesorter.h
+           dcmseg/include/dcmtk/dcmseg/overlaputil.h
+           dcmseg/libsrc/overlaputil.cc
+           dcmseg/libsrc/segment.cc
+
+**** Changes from 2025.11.24 (onken)
+
+- Re-add dcmsign to the Makefile:
+  Accidentally removed in the last commit.
+  Affects: Makefile
+
+- OverlapUtil and some segmentation enhancements:
+  Added OverlapUtil class which allows to detect whether a binary
+  segmentation contains overlapping segments. This supports an upcoming
+  converter for converting binary segmentation objects into labelmap
+  segmentations.
+  Various small enhancements.
+  Added:   dcmfg/include/dcmtk/dcmfg/framesorter.h
+           dcmiod/include/dcmtk/dcmiod/iccexample.h
+           dcmiod/tests/tmacro.cc
+           dcmseg/include/dcmtk/dcmseg/overlaputil.h
+           dcmseg/libsrc/overlaputil.cc
+  Affects: Makefile
+           config/math.cc
+           dcmdata/apps/Makefile.dep
+           dcmdata/libsrc/Makefile.dep
+           dcmect/libsrc/Makefile.dep
+           dcmect/tests/Makefile.dep
+           dcmfg/libsrc/Makefile.dep
+           dcmfg/libsrc/fginterface.cc
+           dcmfg/tests/Makefile.dep
+           dcmiod/include/dcmtk/dcmiod/iodrules.h
+           dcmiod/include/dcmtk/dcmiod/iodtypes.h
+           dcmiod/include/dcmtk/dcmiod/modequipment.h
+           dcmiod/include/dcmtk/dcmiod/modiccprofile.h
+           dcmiod/libsrc/Makefile.dep
+           dcmiod/libsrc/iodmacro.cc
+           dcmiod/libsrc/iodrules.cc
+           dcmiod/libsrc/modequipment.cc
+           dcmiod/libsrc/modiccprofile.cc
+           dcmiod/tests/CMakeLists.txt
+           dcmiod/tests/Makefile.dep
+           dcmiod/tests/Makefile.in
+           dcmiod/tests/tests.cc
+           dcmpmap/libsrc/Makefile.dep
+           dcmseg/Makefile.in
+           dcmseg/include/dcmtk/dcmseg/segdoc.h
+           dcmseg/include/dcmtk/dcmseg/segment.h
+           dcmseg/include/dcmtk/dcmseg/segtypes.h
+           dcmseg/include/dcmtk/dcmseg/segutils.h
+           dcmseg/libsrc/CMakeLists.txt
+           dcmseg/libsrc/Makefile.dep
+           dcmseg/libsrc/Makefile.in
+           dcmseg/libsrc/segdoc.cc
+           dcmseg/libsrc/segment.cc
+           dcmseg/libsrc/segtypes.cc
+           dcmseg/libsrc/segutils.cc
+           dcmseg/tests/Makefile.dep
+           dcmseg/tests/Makefile.in
+           dcmsr/apps/Makefile.dep
+           dcmsr/libsrc/Makefile.dep
+           dcmsr/tests/Makefile.dep
+           dcmtract/libsrc/Makefile.dep
+           dcmtract/tests/Makefile.dep
+           ofstd/include/dcmtk/ofstd/ofmath.h
+           ofstd/libsrc/ofmath.cc
+
+**** Changes from 2025.11.23 (onken)
+
+- Updated copyright date.
+  Affects: dcmnet/include/dcmtk/dcmnet/scppool.h
+
+- Fix potential crashes and endless loop:
+  Fix crash when worker thread reports to the owner pool after destructor
+  of the pool was called.
+  There is no guarantee that all worker threads have completed their work
+  when when m_runMode is set to SHUTDOWN. Added an additional condition to
+  the while loop to wait until all workers have completed their tasks and
+  reported to the pool. After that it's guarantied that all workers are in
+  the m_workerIdle list and can be safely joined.
+  ---
+  Fixed two cases that make destructor of DcmBaseSCPPool never exit.
+  Current implementation of DcmBaseSCPPool's destructor waits for the
+  m_runMode to be set to SHUTDOWN. If m_runMode never set to SHUTDOWN the
+  destructor will wait forever in the 'while' cycle. Two cases when
+  m_runMode is not set to SHUTDOWN:
+  Case 1: The m_runMode won't be set to SHUTDOWN if
+  DcmBaseSCPPool::listen() was never called.
+  Fix:
+  Changed default value of m_runMode from LISTEN to SHUTDOWN. The
+  m_runMode is set to LISTEN inside of the DcmBaseSCPPool::listen()
+  function.
+  Case 2:
+  Call to initializeNetwork() in the DcmBaseSCPPool::listen() function
+  might return bad condition. In that case m_runMode won't be set to
+  SHUTDOWN due to early return.
+  Fix:
+  Add a call to the newly added finishListening() function in case of
+  early return.
+  Thanks to GitHub user Vovasch for the report and patch.
+  Affects: dcmnet/include/dcmtk/dcmnet/scppool.h
+           dcmnet/libsrc/scppool.cc
+
+**** Changes from 2025.11.21 (riesmeier)
+
+- Updated Context Group classes for DICOM 2025e:
+  Updated automatically generated Context Group classes for the latest
+  release of the DICOM standard. All supported classes were updated,
+  even though there were no changes to most of them.
+  Affects: dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
+           dcmsr/libcmr/cid100.cc
+           dcmsr/libcmr/cid10013.cc
+           dcmsr/libcmr/cid10033.cc
+           dcmsr/libcmr/cid11.cc
+           dcmsr/libcmr/cid218.cc
+           dcmsr/libcmr/cid244.cc
+           dcmsr/libcmr/cid247.cc
+           dcmsr/libcmr/cid29.cc
+           dcmsr/libcmr/cid4020.cc
+           dcmsr/libcmr/cid4021.cc
+           dcmsr/libcmr/cid4031.cc
+           dcmsr/libcmr/cid42.cc
+           dcmsr/libcmr/cid6147.cc
+           dcmsr/libcmr/cid7021.cc
+           dcmsr/libcmr/cid7181.cc
+           dcmsr/libcmr/cid7445.cc
+           dcmsr/libcmr/cid7452.cc
+           dcmsr/libcmr/cid7453.cc
+           dcmsr/libcmr/cid7464.cc
+           dcmsr/libcmr/cid7469.cc
+           dcmsr/libcmr/cid7551.cc
+
+- Updated code definitions for DICOM 2025e:
+  Updated automatically generated code definitions for coding schemes
+  "DCM", "NCIt" and "UMLS" based on the latest release of the DICOM
+  standard.
+  Affects: dcmsr/include/dcmtk/dcmsr/codes/dcm.h
+           dcmsr/include/dcmtk/dcmsr/codes/ncit.h
+           dcmsr/include/dcmtk/dcmsr/codes/umls.h
+
+- Updated data dictionary for DICOM 2025e:
+  Updated data dictionary for the latest release of the DICOM standard,
+  although there were no changes (compared to the previous release).
+  Affects: dcmdata/data/dicom.dic
+           dcmdata/include/dcmtk/dcmdata/dcdeftag.h
+           dcmdata/libsrc/dcdictbi.cc
+
+**** Changes from 2025.11.17 (riesmeier)
+
+- Made use of getDestinationEncoding():
+  Call getDestinationEncoding() method instead of using the member
+  variable DestinationEncoding directly. This allows for overwriting
+  the destination encoding in a derived class.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the
+  proposal and use case.
+  Affects: dcmdata/libsrc/dcspchrs.cc
+
+**** Changes from 2025.11.15 (eichelberg)
+
+- Fixed minor warning on C++20 build.
+  Affects: dcmnet/apps/storescp.cc
+
+**** Changes from 2025.11.14 (eichelberg)
+
+- Added storescp option --max-associations:
+  Added a new command line option --max-associations to storescp that allows
+  the user to limit the number of network associations handled in parallel
+  when storescp is running in --fork mode. When the maximum number of child
+  processes is running, further incoming requests are kept on the listen
+  backlog until either a child process has ended or the request times out.
+  On Posix systems, this function uses the SIGCHLD signal to keep track of
+  child processes. On Windows, a list of child processes together with
+  RegisterWaitForSingleObject() is used instead.
+  Affects: dcmnet/apps/storescp.cc
+           dcmnet/docs/storescp.man
+
+**** Changes from 2025.11.13 (eichelberg)
+
+- Added callback parameter to "request fork" function:
+  Added an optional callback function pointer as a parameter to
+  DUL_requestForkOnTransportConnectionReceipt(). The callback will
+  only be used on Windows and on that platform will pass a handle
+  to the child process that has been created in the network module
+  to serve the incoming network assocation. The handle can be
+  used to maintain a list and count of active child processes
+  on Windows, where no SIGCHLD signal is available that automatically
+  notifies the parent process when a child process has ended.
+  Affects: dcmnet/include/dcmtk/dcmnet/dul.h
+           dcmnet/libsrc/dul.cc
+
+**** Changes from 2025.11.07 (eichelberg)
+
+- Fixed man page on Windows.
+  Affects: dcmdata/docs/img2dcm.man
+
+- Fixed man page on Windows.
+  Affects: dcmdata/docs/dcm2json.man
+
+**** Changes from 2025.11.03 (riesmeier)
+
+- Moved new regression tests to another file.
+  Affects: dcmdata/tests/tchval.cc
+           dcmdata/tests/tests.cc
+           dcmdata/tests/tvrdatim.cc
+
+- Fixed issue with VR scanner for "DateTime" values:
+  Fixed an issue with the VR scanner for an incorrect definition of
+  "DateTime" (DT) values: The UTC suffix "+0000" was not supported,
+  which was quite surprising since this is the current timezone for
+  for the UK, for example.
+  Also added a new regression test to check whether the VR scanner
+  correctly accepts and rejects certain timezones for DT values.
+  Thanks to Jez Cooke <jez.cooke@hamamatsu.eu> and Kade Rashid
+  <kade.rashid@hamamatsu.eu> for the report and suggested fix.
+  Affects: dcmdata/libsrc/vrscanl.c
+           dcmdata/libsrc/vrscanl.l
+           dcmdata/tests/tests.cc
+           dcmdata/tests/tvrdatim.cc
+
+- Fixed source code formatting.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcvrae.h
+           dcmnet/apps/dcmrecv.cc
+           dcmnet/apps/movescu.cc
+           dcmnet/apps/storescp.cc
+           dcmnet/docs/dcmrecv.man
+           dcmqrdb/apps/dcmqrscp.cc
+           dcmwlm/apps/wlcefs.cc
+
+**** Changes from 2025.11.02 (eichelberg)
+
+- Added IPv6 support to DCMTK's association acceptors:
+  Added support for explicitly selecting the IP protocol version (including
+  IPv6 and a dual-stack IPv4/v6 mode) to all DCMTK "server" applications
+  that accept incoming DICOM associations.
+  Thanks to Sobhita Mercy <sobhitamercy@gmail.com> for this contribution.
+  This closes GitHub pull request #128.
+  Affects: dcmnet/apps/dcmrecv.cc
+           dcmnet/apps/movescu.cc
+           dcmnet/apps/storescp.cc
+           dcmnet/docs/dcmrecv.man
+           dcmnet/docs/movescu.man
+           dcmnet/docs/storescp.man
+           dcmnet/include/dcmtk/dcmnet/dul.h
+           dcmnet/libsrc/dul.cc
+           dcmpstat/apps/dcmprscp.cc
+           dcmpstat/apps/dcmpsrcv.cc
+           dcmpstat/etc/dcmpstat.cfg
+           dcmpstat/include/dcmtk/dcmpstat/dviface.h
+           dcmpstat/include/dcmtk/dcmpstat/dvpscf.h
+           dcmpstat/libsrc/dviface.cc
+           dcmpstat/libsrc/dvpscf.cc
+           dcmqrdb/apps/dcmqrscp.cc
+           dcmqrdb/docs/dcmqrscp.man
+           dcmqrdb/libsrc/dcmqrcbm.cc
+           dcmwlm/apps/wlcefs.cc
+           dcmwlm/docs/wlmscpfs.man
+
+**** Changes from 2025.10.31 (eichelberg)
+
+- Added missing includes.
+  Affects: dcmdata/libsrc/dcdocdec.cc
+
+**** Changes from 2025.10.30 (eichelberg)
+
+- Switch stdout to binary on Windows:
+  Switch stdout to binary mode on Windows when decapsulating
+  an encapsulated document to stdout, to prevent CR/LF conversion.
+  Affects: dcmdata/libsrc/dcdocdec.cc
+
+**** Changes from 2025.10.29 (eichelberg)
+
+- Fixed minor warnings.
+  Affects: dcmdata/libsrc/dcjsonrd.cc
+
+**** Changes from 2025.10.28 (eichelberg)
+
+- DcmJSONReader::clear() now prevents double delete:
+  DcmJSONReader::clear() now sets jsonDataset_ and tokenArray_ to NULL after
+  deletion to prevent double-delete when the object is reused.
+  Thanks to GitHub user "Oss-Auditor" for the pull request.
+  This closes GitHub PR #131.
+  Affects: dcmdata/libsrc/dcjsonrd.cc
+
+**** Changes from 2025.10.25 (riesmeier)
+
+- Fixed issues with new command line tool dcmdecap.
+  Affects: dcmdata/apps/Makefile.in
+
+- Added new tools dcmdecap and dcmencap.
+  Affects: .gitignore
+
+**** Changes from 2025.10.25 (eichelberg)
+
+- Fix TCP initialization error message:
+  This fixes the following misleading error message that is printed
+  on Windows when connect() or select() fails:
+  "TCP Initialization Error: No error".
+  Thanks to Github user "luk1337" for the pull request
+  This closes Github pull request #129.
+  Affects: dcmnet/libsrc/dulfsm.cc
+
+- Added dcmdecap and dcmencap to module documentation.
+  Affects: dcmdata/docs/dcmdata.dox
+
+- Added new tool dcmdecap that extracts encapsulated documents:
+  Added new tool dcmencap that  extracts encapsulated documents into
+  separate files. The formerly separate tools dcm2pdf and dcm2cda are
+  now deprecated and act as stubs that call dcmdecap.
+  Added:   dcmdata/apps/dcmdecap.cc
+           dcmdata/docs/dcmdecap.man
+           dcmdata/include/dcmtk/dcmdata/dcdocdec.h
+           dcmdata/libsrc/dcdocdec.cc
+  Affects: dcmdata/apps/CMakeLists.txt
+           dcmdata/apps/Makefile.in
+           dcmdata/apps/dcm2cda.cc
+           dcmdata/apps/dcm2pdf.cc
+           dcmdata/docs/dcm2cda.man
+           dcmdata/docs/dcm2pdf.man
+           dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/libsrc/CMakeLists.txt
+           dcmdata/libsrc/Makefile.in
+           dcmdata/libsrc/dcerror.cc
+
+**** Changes from 2025.10.24 (eichelberg)
+
+- Fixed dcmAcceptOddAttributeLength implementation:
+  The global dcmdata setting 'dcmAcceptOddAttributeLength' determines how
+  illegal data elements with odd length are handled when reading.
+  By default, DCMTK accepts odd-length elements and silently pads
+  them to even length. If this setting is set to false, DCMTK instead
+  assumes that the attribute value is in fact even length and that
+  only the value of the length field is wrong, and increases the
+  length field by 1. This behaviour, which is not the default,
+  did not work correctly for elements larger than 4 kBytes, which are
+  skipped when reading from file and only loaded on demand later.
+  This has now been fixed.
+  Affects: dcmdata/libsrc/dcelem.cc
+
+**** Changes from 2025.10.17 (riesmeier)
+
+- Made DcmItem::updateSpecificCharacterSet() public:
+  The DcmItem::updateSpecificCharacterSet() method has been made public,
+  so that it can be called directly if needed (which is only true in
+  special use cases).
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the
+  original report.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcitem.h
+           dcmdata/include/dcmtk/dcmdata/dcspchrs.h
+
+**** Changes from 2025.10.16 (riesmeier)
+
+- Made sure not to use incompatible options:
+  Made sure that the options --ignore-mlut-depth and --ignore-vlut-depth
+  are not used together with --check-lut-depth, as they are mutually
+  exclusive.
+  Affects: dcmapps/include/dcmtk/dcmapps/dcm2img.h
+
+- Removed last (empty) entry from UID name map:
+  Removed the last (empty) entry from the central UID name mapping array
+  because it serves no purpose.
+  Thanks to DCMTK forum user "Shaeto" for the original report.
+  Affects: dcmdata/libsrc/dcuid.cc
+
+- Warn if Photometric Interpretation is missing:
+  Just warn if Photometric Interpretation is missing, when ACR-NEMA
+  compatibility is enabled.
+  Affects: dcmimgle/libsrc/didocu.cc
+
+**** Changes from 2025.10.07 (riesmeier)
+
+- Updated code definitions for DICOM 2025d:
+  Updated automatically generated code definitions for coding scheme "DCM".
+  For the coding schemes "NCIt" and "UMLS", there were no changes.
+  Affects: dcmsr/include/dcmtk/dcmsr/codes/dcm.h
+           dcmsr/include/dcmtk/dcmsr/codes/ncit.h
+           dcmsr/include/dcmtk/dcmsr/codes/umls.h
+
+- Updated data dictionary for DICOM 2025d:
+  Updated data dictionary for the latest edition of the DICOM standard.
+  Affects: dcmdata/data/dicom.dic
+           dcmdata/include/dcmtk/dcmdata/dcdeftag.h
+           dcmdata/libsrc/dcdictbi.cc
+
+**** Changes from 2025.09.25 (eichelberg)
+
+- Fixed minor warning.
+  Affects: dcmqrdb/include/dcmtk/dcmqrdb/dcmqrcbm.h
+
+**** Changes from 2025.09.24 (eichelberg)
+
+- Enabled the use of TLS for sub-associations:
+  Enabled the use of TLS for storage sub-associations in dcmqrscp,
+  which completes the TLS support for the C-MOVE retrieve service.
+  Thanks to Nikolai Beck (GitHub user nbeck-SMT) for the pull request.
+  This closes GitHub PR #127.
+  Affects: dcmqrdb/include/dcmtk/dcmqrdb/dcmqrcbm.h
+           dcmqrdb/libsrc/dcmqrcbm.cc
+           dcmqrdb/libsrc/dcmqrsrv.cc
+
+- Added JPEG decoder option for preserving BitsStored:
+  Added a codec parameter and corresponing command line options in dcmdjpeg
+  and dcm2img that allow the value of Bits Stored to be preserved even if
+  the value in the JPEG bitstream is smaller than the value in the DICOM header.
+  This may help with correctly decoding some defective DICOM images.
+  This closes DCMTK issue #1054.
+  Affects: dcmapps/docs/dcm2img.man
+           dcmapps/include/dcmtk/dcmapps/dcm2img.h
+           dcmjpeg/apps/dcmdjpeg.cc
+           dcmjpeg/docs/dcmdjpeg.man
+           dcmjpeg/include/dcmtk/dcmjpeg/djcparam.h
+           dcmjpeg/include/dcmtk/dcmjpeg/djdecode.h
+           dcmjpeg/libsrc/djcodecd.cc
+           dcmjpeg/libsrc/djcparam.cc
+           dcmjpeg/libsrc/djdecode.cc
+
+**** Changes from 2025.09.19 (eichelberg)
+
+- Fixed off-by-one buffer overrun.
+  Affects: dcmdata/libsrc/dcencdoc.cc
+
+**** Changes from 2025.09.18 (eichelberg)
+
+- Fixed inconsistencies in command line options.
+  Affects: dcmdata/docs/dcmencap.man
+           dcmdata/libsrc/dcencdoc.cc
+
+- Fixed minor warnings.
+  Affects: dcmdata/libsrc/dcencdoc.cc
+           ofstd/libsrc/ofstub.cc
+
+**** Changes from 2025.09.17 (eichelberg)
+
+- Updated man pages for deprecated tools.
+  Affects: dcmdata/docs/cda2dcm.man
+           dcmdata/docs/pdf2dcm.man
+           dcmdata/docs/stl2dcm.man
+
+- Made depreciation warnings more prominent.
+  Affects: ofstd/libsrc/ofstub.cc
+
+**** Changes from 2025.09.17 (onken)
+
+- Fix reusability of SCP threads in pool:
+  Added more debug messages. Fixed some typos in TLS pool test case and
+  classes and make use OFStandard instead of custom methods.
+  Affects: dcmnet/include/dcmtk/dcmnet/scppool.h
+           dcmnet/include/dcmtk/dcmnet/scpthrd.h
+           dcmnet/libsrc/scppool.cc
+           dcmnet/libsrc/scpthrd.cc
+           dcmtls/tests/tscuscptls.cc
+
+**** Changes from 2025.09.17 (eichelberg)
+
+- Minor improvements for dcmencap:
+  The command line options for device data can now also be used when
+  encapsulating PDF and CDA documents, where the corresponding attributes
+  are optional. Also improved some warning/error messages.
+  Affects: dcmdata/docs/dcmencap.man
+           dcmdata/libsrc/dcencdoc.cc
+
+- Added consistency check for --series-from option:
+  Added consistency check for dcmencap's --series-from option to make sure
+  that series with different Modality values do not get merged.
+  Furthermore, fixed an inconsistency in the man page.
+  Affects: dcmdata/docs/dcmencap.man
+           dcmdata/include/dcmtk/dcmdata/dcencdoc.h
+           dcmdata/libsrc/dcencdoc.cc
+
+- Added new tool dcmencap that encapsulates documents:
+  Added new tool dcmencap that encapsulates documents of all types currently
+  supported in DICOM (PDF, CDA, STL, MTL and OBJ) into their corresponding
+  Encapulated Document Storage SOP Class in DICOM. The formerly separate tools
+  pdf2dcm, cda2dcm and stl2dcm are now deprecated and act as stubs that call
+  dcmencap. The document format (and, thus, SOP class) is now automatically
+  determined by default.
+  Added:   dcmdata/apps/dcmencap.cc
+           dcmdata/docs/dcmencap.man
+  Affects: dcmdata/apps/CMakeLists.txt
+           dcmdata/apps/Makefile.dep
+           dcmdata/apps/Makefile.in
+           dcmdata/apps/cda2dcm.cc
+           dcmdata/apps/pdf2dcm.cc
+           dcmdata/apps/stl2dcm.cc
+           dcmdata/include/dcmtk/dcmdata/dcencdoc.h
+           dcmdata/libsrc/dcencdoc.cc
+
+**** Changes from 2025.09.15 (onken)
+
+- Fixed leak in SCP Pool class, re-use threads:
+  In the old implementation busy worker threads have been joined but not
+  deleted or re-used.
+  The updated implementation re-uses busy workers by putting them back
+  into the pool of idle threads. All threads (if ever busy or not) are now
+  joined and deleted when the pool is being destroyed.
+  The test has been expanded to use a more thread-safe approach on result
+  variables and to also tests thread-reuse for threads that had been put
+  back into the idle pool before.
+  Thanks to Chuang Zhao <zhaocccchuang@163.com> for the report and
+  analysis.
+  Affects: dcmnet/libsrc/scppool.cc
+           dcmnet/tests/tpool.cc
+
+**** Changes from 2025.09.10 (riesmeier)
+
+- Fixed typo in comment:
+  Thanks to GitHub user "mrbean-bremen" for the report (see PR #124).
+  Affects: .github/workflows/cmake-win.yml
+
+**** Changes from 2025.09.08 (riesmeier)
+
+- Added check of "writeMode" to write() method:
+  Added check of "writeMode" parameter to DcmFileFormat::write() method,
+  so that only a dataset (without meta header) is written if its value
+  is EWM_dataset, i.e. if requested by the caller. This behavior is now
+  consistent with the DcmFileFormat::saveFile() method.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the
+  original report on this issue.
+  Affects: dcmdata/libsrc/dcdatset.cc
+           dcmdata/libsrc/dcfilefo.cc
+
+**** Changes from 2025.09.03 (riesmeier)
+
+- Converted array index to unsigned integer value:
+  Converted array index to unsigned integer value to avoid warning message
+  reported by gcc 14 on Solaris, e.g. with -Wall or -Wchar-subscripts:
+  "warning: array subscript has type 'char'"
+  Also slightly restructured code to make it more readable.
+  Affects: dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+
+**** Changes from 2025.08.29 (onken)
+
+- Replace old-style casts to avoid compiler warnings.
+  Affects: dcmiod/include/dcmtk/dcmiod/iodtypes.h
+           dcmiod/tests/tpalette.cc
+
+**** Changes from 2025.08.28 (onken)
+
+- Fix linker errors with dupl. method definitions.
+  Affects: dcmiod/include/dcmtk/dcmiod/iodtypes.h
+           dcmiod/libsrc/iodtypes.cc
+
+**** Changes from 2025.08.25 (onken)
+
+- Fix another data type size warning.
+  Affects: dcmfg/libsrc/fginterface.cc
+
+**** Changes from 2025.08.22 (eichelberg)
+
+- Set implementation information at runtime:
+  Added APIs that allow the user to set the Implementation Class UID and
+  Implementation Version name at runtime while writing a DICOM file,
+  processing an incoming network association request or configuring
+  and outgoing network association request.
+  Thanks to Vasyl Horbatenko (GitHub user doskachok) for the pull request.
+  This closes GitHub PR #68 and #69.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcfilefo.h
+           dcmdata/libsrc/dcfilefo.cc
+           dcmnet/include/dcmtk/dcmnet/assoc.h
+           dcmnet/include/dcmtk/dcmnet/scpcfg.h
+           dcmnet/include/dcmtk/dcmnet/scu.h
+           dcmnet/libsrc/assoc.cc
+           dcmnet/libsrc/scp.cc
+           dcmnet/libsrc/scpcfg.cc
+           dcmnet/libsrc/scppool.cc
+           dcmnet/libsrc/scu.cc
+
+**** Changes from 2025.08.22 (riesmeier)
+
+- Slightly enhanced new functionality of LUT class:
+  Slightly enhanced new functionality of the LUT class and fixed some
+  issues introduced with a recent commit (71567ae84).
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diluptab.h
+           dcmimgle/libsrc/diluptab.cc
+
+**** Changes from 2025.08.22 (onken)
+
+- Remove superfluous comment line.
+  Affects: .gitignore
+
+- Restore old GitHub actions rules.
+  Affects: .github/workflows/cmake-win.yml
+
+- Use space between template angle brackets.
+  Affects: dcmfg/include/dcmtk/dcmfg/fginterface.h
+           dcmfg/libsrc/fginterface.cc
+           dcmseg/include/dcmtk/dcmseg/segdoc.h
+
+- Remove test app.
+  Affects: dcmseg/CMakeLists.txt
+  Removed: dcmseg/apps/CMakeLists.txt
+           dcmseg/apps/check_segs.md
+           dcmseg/apps/check_segs.sh
+           dcmseg/apps/segdigest.cc
+
+**** Changes from 2025.08.21 (onken)
+
+- Fix debug output.
+  Affects: dcmiod/include/dcmtk/dcmiod/iodtypes.h
+
+- Remove override specificier:
+  Marking methods with "override" is only perrmitted
+  in C+11 or later.
+  Affects: dcmect/include/dcmtk/dcmect/enhanced_ct.h
+           dcmfg/include/dcmtk/dcmfg/fginterface.h
+           dcmiod/include/dcmtk/dcmiod/iodimage.h
+           dcmpmap/include/dcmtk/dcmpmap/dpmparametricmapiod.h
+           dcmseg/include/dcmtk/dcmseg/segdoc.h
+
+- Fix some compiler warnings.
+  Affects: dcmfg/include/dcmtk/dcmfg/fginterface.h
+           dcmfg/libsrc/fginterface.cc
+           dcmseg/include/dcmtk/dcmseg/segutils.h
+
+- Added Labelmap Segmentation Support:
+  Added support for creating, writing and reading Labelmap Segmentation
+  Storage objects to the DCMTK dcmseg module. This also requires an update
+  of the underlying DCMTK dcmfg (functional group) and dcmiod (common iod
+  support) modules (libraries), e.g. to add new DICOM modules (such as the
+  Palette Color Lookup Table module) and to generalize pixel data handling
+  to support 16 bit pixel data in segmentations. This also led to updates
+  in related "higher" DCMTK modules like such as dcmect.
+  Furthermore, reading and writing segmentation objects now can make use
+  of threads in order to write the per-frame functional group information
+  which can lead to large performance gains in case the object contains
+  thousands of frames. The feature has been built into the dcmfg module
+  and by default, is turned off (i.e. only a single thread is used). One
+  reason is that DCMTK does not support the C++ "<thread>" API and thus
+  cannot determine the number of available CPU cores on its own. Thus, the
+  user has to enable the feature when using the dcmfg (FGInterface) or
+  more for segmentations, the DcmSegmentation API. Other objects like the
+  Enhanced CT objects within DCMTK's dcmect module can also make use the
+  the threaded API, but the related dcmfg feature is not yet exposed to
+  their public APIs. To see how the threaded approach can be used, look at
+  dcmseg/tests/tbigdim.cc which reads and writes per-frame functional
+  groups using 16 threads (without checking the available cores of the
+  system).
+  Furthermore, a few bugs have been fixed, and minor enhancements have
+  been added.
+  Added:   dcmiod/include/dcmtk/dcmiod/modiccprofile.h
+           dcmiod/include/dcmtk/dcmiod/modpalettecolorlut.h
+           dcmiod/libsrc/modiccprofile.cc
+           dcmiod/libsrc/modpalettecolorlut.cc
+           dcmiod/tests/ticcprofile.cc
+           dcmiod/tests/tpalette.cc
+           dcmseg/apps/CMakeLists.txt
+           dcmseg/apps/check_segs.md
+           dcmseg/apps/check_segs.sh
+           dcmseg/apps/segdigest.cc
+           dcmseg/tests/tlabelmap.cc
+           dcmseg/tests/tpacking.cc
+           ofstd/include/dcmtk/ofstd/diag/vsconstexp.def
+  Affects: .github/workflows/cmake-win.yml
+           .gitignore
+           ANNOUNCE
+           CMake/GenerateDCMTKConfigure.cmake
+           Makefile
+           config/modules
+           dcmdata/apps/Makefile.dep
+           dcmdata/apps/cda2dcm.cc
+           dcmdata/libdcxml/Makefile.dep
+           dcmdata/libi2d/Makefile.dep
+           dcmdata/libsrc/Makefile.dep
+           dcmdata/tests/Makefile.dep
+           dcmect/include/dcmtk/dcmect/enhanced_ct.h
+           dcmect/libsrc/enhanced_ct.cc
+           dcmect/tests/t_huge_concat.cc
+           dcmfg/include/dcmtk/dcmfg/concatenationcreator.h
+           dcmfg/include/dcmtk/dcmfg/concatenationloader.h
+           dcmfg/include/dcmtk/dcmfg/fg.h
+           dcmfg/include/dcmtk/dcmfg/fgderimg.h
+           dcmfg/include/dcmtk/dcmfg/fginterface.h
+           dcmfg/include/dcmtk/dcmfg/fgseg.h
+           dcmfg/include/dcmtk/dcmfg/fgtypes.h
+           dcmfg/libsrc/Makefile.dep
+           dcmfg/libsrc/concatenationcreator.cc
+           dcmfg/libsrc/concatenationloader.cc
+           dcmfg/libsrc/fg.cc
+           dcmfg/libsrc/fgderimg.cc
+           dcmfg/libsrc/fginterface.cc
+           dcmfg/libsrc/fgseg.cc
+           dcmfg/libsrc/fgtypes.cc
+           dcmfg/tests/Makefile.dep
+           dcmfg/tests/t_concatenation_loader.cc
+           dcmimage/libsrc/Makefile.dep
+           dcmimgle/include/dcmtk/dcmimgle/diluptab.h
+           dcmimgle/libsrc/Makefile.dep
+           dcmimgle/libsrc/diluptab.cc
+           dcmiod/include/dcmtk/dcmiod/iodimage.h
+           dcmiod/include/dcmtk/dcmiod/iodtypes.h
+           dcmiod/include/dcmtk/dcmiod/iodutil.h
+           dcmiod/include/dcmtk/dcmiod/modbase.h
+           dcmiod/include/dcmtk/dcmiod/modgeneralimage.h
+           dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h
+           dcmiod/libsrc/CMakeLists.txt
+           dcmiod/libsrc/Makefile.dep
+           dcmiod/libsrc/Makefile.in
+           dcmiod/libsrc/iodmacro.cc
+           dcmiod/libsrc/iodtypes.cc
+           dcmiod/libsrc/iodutil.cc
+           dcmiod/libsrc/modmultiframedimension.cc
+           dcmiod/tests/CMakeLists.txt
+           dcmiod/tests/Makefile.dep
+           dcmiod/tests/Makefile.in
+           dcmiod/tests/tchecks.cc
+           dcmiod/tests/tests.cc
+           dcmjpeg/libsrc/Makefile.dep
+           dcmnet/apps/Makefile.dep
+           dcmpmap/include/dcmtk/dcmpmap/dpmparametricmapiod.h
+           dcmpmap/libsrc/dpmparametricmapiod.cc
+           dcmpstat/apps/Makefile.dep
+           dcmpstat/libsrc/Makefile.dep
+           dcmseg/CMakeLists.txt
+           dcmseg/include/dcmtk/dcmseg/segdoc.h
+           dcmseg/include/dcmtk/dcmseg/segment.h
+           dcmseg/include/dcmtk/dcmseg/segtypes.h
+           dcmseg/include/dcmtk/dcmseg/segutils.h
+           dcmseg/libsrc/Makefile.dep
+           dcmseg/libsrc/segdoc.cc
+           dcmseg/libsrc/segment.cc
+           dcmseg/libsrc/segtypes.cc
+           dcmseg/libsrc/segutils.cc
+           dcmseg/tests/CMakeLists.txt
+           dcmseg/tests/Makefile.dep
+           dcmseg/tests/Makefile.in
+           dcmseg/tests/tbigdim.cc
+           dcmseg/tests/tconcat_binary.cc
+           dcmseg/tests/tests.cc
+           dcmseg/tests/troundtrip.cc
+           dcmseg/tests/tutils.cc
+           dcmsr/libsrc/Makefile.dep
+           dcmtls/libsrc/tlsfmacr.h
+           dcmtract/include/dcmtk/dcmtract/trctrackset.h
+           oficonv/libsrc/Makefile.dep
+           ofstd/include/dcmtk/ofstd/ofdiag.h
+           ofstd/libsrc/Makefile.dep
+           ofstd/tests/Makefile.dep
+
+**** Changes from 2025.08.21 (eichelberg)
+
+- Added method for accessing a DICOM file preamble:
+  Added a method that allows the user to access the file preamble after reading
+  a DICOM file.
+  This closes DCMTK issue #185.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcmetinf.h
+           dcmdata/libsrc/dcmetinf.cc
+
+**** Changes from 2025.08.19 (eichelberg)
+
+- Improved CMake code for static builds:
+  The variables containing the lists of additional libraries that need to be
+  linked when a certain static library is linked (such as
+  LIBPNG_EXTRA_LIBS_STATIC) are now also taken into account on Windows.
+  Furthermore, added some improvements for static builds on Debian Linux.
+  Thanks to Khang Trần <khangthk@gmail.com> for the pull request.
+  This closes DCMTK PR #104.
+  Affects: CMake/3rdparty.cmake
+           CMake/dcmtkPrepare.cmake
+
+- Fixed sample code:
+  Added proper null termination to string in sample program.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull request.
+  This closes GitHub PR #123.
+  Affects: oficonv/docs/oficonv.dox
+
+- Link libnsl and libsocket only when required:
+  DCMTK no longer unconditionally tests or links against `nsl` and `socket`.
+  These libraries are now only considered on pre-11.4 Solaris systems,
+  where functions such as `gethostbyname` were historically provided
+  outside libc. This avoids dependencies on libraries that may directly
+  or indirectly pull in a different OpenSSL version.
+  Thanks to Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
+  for the pull request.
+  This closes GitHub PR #125.
+  Affects: CMake/dcmtkPrepare.cmake
+
+**** Changes from 2025.08.19 (riesmeier)
+
+- Reduced number of warnings (gcc -Wconversion):
+  Reduced number of warnings reported by gcc with extra warning option
+  -Wconversion.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+
+**** Changes from 2025.08.18 (riesmeier)
+
+- Fixed warning reported by Visual Studio.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+
+- Fixed off-by-one error when processing an image:
+  Fixed an off-by-one error when processing an unusual encoding of a DICOM
+  image, e.g. with partial access to the pixel data. The internal handling
+  of the input pixel data with a certain combination of VR, Bits Allocated
+  and Bits Stored (see "case 2c") was missing the final pixel value (for
+  images with an odd number of bytes) in size and could, therefore, result
+  in an undefined behavior (incl. an out-of-bounds write to a memory block
+  on the heap).
+  Thanks to drak <dr4k.sec@gmail.com> for the report and sample file.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+
+- Fixed issue with commit 7ad81d69b:
+  Fixed an issue with recently committed changes that fix a problem with
+  invalid YBR_FULL images
+  Affects: dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+
+**** Changes from 2025.08.18 (eichelberg)
+
+- Fixed metaheader generation in dcmodify and dcmconv:
+  The dcmodify and dcmconv tools incorrectly changed the MediaStorageSOPClassUID
+  and MediaStorageSOPInstanceUID in the DICOM meta-header when processing
+  DICOMDIR files. This was caused by the EWM_createNewMeta write mode,
+  which was introduced as the default behavior for DcmFileFormat::saveFile()
+  in DCMTK 3.6.6. This option deleted and re-created the entire meta-header
+  before writing the file. When the SOP Class UID and the SOP Instance UID
+  were not present in the main dataset, a private SOP class with a
+  newly generated SOP Instance UID were written. This is now fixed:
+  MediaStorageSOPClassUID and MediaStorageSOPInstanceUID are preserved
+  when not present in the main dataset.
+  Furthermore, dcmodify's "--no-meta-uid" command line option, which was
+  apparently broken since DCMTK 3.6.6, is now also fixed.
+  This closes DCMTK issue #1148.
+  Affects: dcmdata/apps/mdfdsman.cc
+           dcmdata/include/dcmtk/dcmdata/dctypes.h
+           dcmdata/libsrc/dcfilefo.cc
+
+- Added note on character set conversion:
+  Added a note in the API documentation pointing out that the character set
+  conversion code will not perform a thorough validation of the input strings,
+  i.e. characters that are permitted in the source character set but forbidden
+  in DICOM will be converted without warning or error.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcitem.h
+           dcmdata/include/dcmtk/dcmdata/dcspchrs.h
+
+**** Changes from 2025.08.15 (riesmeier)
+
+- Fixed issue with invalid "YBR_FULL" DICOM images:
+  Fixed an issue when processing an invalid DICOM image with a Photometric
+  Interpretation of "YBR_FULL" and a Planar Configuration of "1" where
+  the number of pixels stored does not match the expected number of pixels
+  (much too less). Now, the pixel data of such an image is not processed
+  at all, but an empty image (black pixels) is created instead. The user
+  is warned about this by an appropriate log message.
+  Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
+  and the sample file (PoC).
+  Affects: dcmimage/include/dcmtk/dcmimage/dicopxt.h
+           dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+           dcmimgle/libsrc/dcmimage.cc
+
+**** Changes from 2025.08.11 (eichelberg)
+
+- Improved documentation of initializeXfer() method.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcdatset.h
+
+- Initialize dataset transfer syntax when reading file:
+  Added code to initialize the transfer syntax of the dataset component
+  when reading a DICOM file (DcmFileFormat), in order to make sure that
+  the right transfer syntax will be reported even if the dataet is empty.
+  This closes DCMTK issue #1159.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcdatset.h
+           dcmdata/libsrc/dcdatset.cc
+           dcmdata/libsrc/dcfilefo.cc
+
+**** Changes from 2025.08.05 (eichelberg)
+
+- Moved pragma to separate include file:
+  Moved a pragma needed for compilation with gcc on MacOS
+  into a separate include file referenced by the macro
+  DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC.
+  Added:   ofstd/include/dcmtk/ofstd/diag/clangprg.def
+  Affects: dcmdata/include/dcmtk/dcmdata/dcmxml/xml2dcm.h
+           dcmdata/libdcxml/xml2dcm.cc
+           dcmsr/apps/xml2dsr.cc
+           dcmsr/include/dcmtk/dcmsr/dsrxmlc.h
+           ofstd/include/dcmtk/ofstd/ofdiag.h
+
+**** Changes from 2025.08.04 (eichelberg)
+
+- Added method for activating the list of ciphersuites:
+  Added a method for activating the list of ciphersuites defined through
+  DcmTLSSCU::setTLSProfile() and DcmTLSSCU::addCipherSuite(). Previously
+  this list was never actually activated.
+  Thanks to Ben Chen <Ben.Chen@intusurg.com> for the bug report and patch.
+  Affects: dcmtls/include/dcmtk/dcmtls/tlsscu.h
+           dcmtls/libsrc/tlsscu.cc
+
+**** Changes from 2025.08.03 (eichelberg)
+
+- Added missing include on Windows.
+  Affects: dcmdata/libsrc/dcjsonrd.cc
+
+**** Changes from 2025.08.02 (eichelberg)
+
+- Added support for file BulkDataURIs in json2dcm:
+  Added support for reading bulk data from files in the local filesystem
+  when converting a dataset in DICOM JSON encoding to a DICOM file.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+           dcmdata/include/dcmtk/dcmdata/dcjsonrd.h
+           dcmdata/libsrc/dcjsonrd.cc
+
+**** Changes from 2025.07.31 (eichelberg)
+
+- Fixed OFStandard API documentation:
+  Removed reference to big endian byte order in Base64 encoder and
+  decoder methods in class OFStandard since this does not apply to DICOM.
+  Affects: ofstd/include/dcmtk/ofstd/ofstd.h
+
+**** Changes from 2025.07.24 (eichelberg)
+
+- Added error code for unsupported URI type.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/libsrc/dcerror.cc
+
+- Added default for bulk data size in help output.
+  Affects: dcmdata/apps/dcm2json.cc
+           dcmdata/docs/dcm2json.man
+
+**** Changes from 2025.07.16 (riesmeier)
+
+- Updated Context Group classes for DICOM 2025c:
+  Updated automatically generated Context Group classes for the latest
+  edition of the DICOM standard. All supported classes were updated,
+  even though there were no changes to most of them.
+  Affects: dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
+           dcmsr/libcmr/cid100.cc
+           dcmsr/libcmr/cid10013.cc
+           dcmsr/libcmr/cid10033.cc
+           dcmsr/libcmr/cid11.cc
+           dcmsr/libcmr/cid218.cc
+           dcmsr/libcmr/cid244.cc
+           dcmsr/libcmr/cid247.cc
+           dcmsr/libcmr/cid29.cc
+           dcmsr/libcmr/cid4020.cc
+           dcmsr/libcmr/cid4021.cc
+           dcmsr/libcmr/cid4031.cc
+           dcmsr/libcmr/cid42.cc
+           dcmsr/libcmr/cid6147.cc
+           dcmsr/libcmr/cid7021.cc
+           dcmsr/libcmr/cid7181.cc
+           dcmsr/libcmr/cid7445.cc
+           dcmsr/libcmr/cid7452.cc
+           dcmsr/libcmr/cid7453.cc
+           dcmsr/libcmr/cid7464.cc
+           dcmsr/libcmr/cid7469.cc
+           dcmsr/libcmr/cid7551.cc
+
+- Updated code definitions for DICOM 2025c:
+  Updated automatically generated code definitions for coding schemes "DCM"
+  and "UMLS". For the coding scheme "NCIt", there were no changes.
+  Affects: dcmsr/include/dcmtk/dcmsr/codes/dcm.h
+           dcmsr/include/dcmtk/dcmsr/codes/ncit.h
+           dcmsr/include/dcmtk/dcmsr/codes/umls.h
+
+- Updated data dictionary for DICOM 2025c:
+  Updated data dictionary for the latest edition of the DICOM standard,
+  which has been released only recently.
+  Affects: dcmdata/data/dicom.dic
+           dcmdata/include/dcmtk/dcmdata/dcdeftag.h
+           dcmdata/libsrc/dcdictbi.cc
+
+**** Changes from 2025.07.12 (riesmeier)
+
+- Replaced tab characters by spaces.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcjsonrd.h
+           dcmdata/libsrc/dcjsonrd.cc
+
+**** Changes from 2025.07.11 (eichelberg)
+
+- Refactored DICOM JSON parser into reusable class:
+  Refactored the DICOM JSON model parser that provides the core functionality
+  of the json2dcm application into a reusable class in the dcmdata library.
+  In this process, the code was also significantly revised and refined.
+  Added:   dcmdata/include/dcmtk/dcmdata/dcjsonrd.h
+           dcmdata/libsrc/dcjsonrd.cc
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/libsrc/CMakeLists.txt
+           dcmdata/libsrc/Makefile.in
+
+**** Changes from 2025.07.10 (riesmeier)
+
+- Replaced wrong term in manpage.
+  Affects: dcmdata/docs/json2dcm.man
+
+- Fixed various spelling and formatting issues.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+**** Changes from 2025.07.09 (eichelberg)
+
+- Fixed warnings from gcc on MacOS 15:
+  The version of libxml2 provided as part of the MacOS 15 development tools
+  contain some Clang specific pragmas that cause warnings when compiling
+  with gcc. These are now suppressed.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcmxml/xml2dcm.h
+           dcmdata/libdcxml/xml2dcm.cc
+           dcmsr/apps/xml2dsr.cc
+           dcmsr/include/dcmtk/dcmsr/dsrxmlc.h
+
+- Removed unneccessary parameter.
+  Affects: dcmdata/apps/json2dcm.cc
+
+**** Changes from 2025.07.08 (eichelberg)
+
+- Added options for handling JSON arrays of datasets:
+  Added command line options for handling JSON arrays of DICOM JSON datasets,
+  which are returned by DICOMweb services such as QIDO-RS or WADO-RS when
+  multiple datasets are returned for one request.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+**** Changes from 2025.07.07 (eichelberg)
+
+- Added --ignore-bulkdata-uri option to json2dcm:
+  Added a command line option that allows json2dcm to ignore bulk data URIs
+  in DICOM JSON files, which are not yet supported. Furthermore revised the
+  logger messages for better consistency and less duplication.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+- Improved json2dcm performance:
+  Improved json2dcm performance, in particular when reading large look-up
+  tables. Also improved consistency of logger output.
+  Affects: dcmdata/apps/json2dcm.cc
+
+**** Changes from 2025.07.01 (riesmeier)
+
+- Made some functions virtual to allow overriding:
+  Made some functions for character set conversion virtual to allow for
+  overriding them in derived classes.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the idea.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcitem.h
+           dcmdata/include/dcmtk/dcmdata/dcspchrs.h
+           dcmdata/libsrc/dcitem.cc
+
+- Do not warn on "Undefind Length" for some VRs:
+  Do not warn when using "Undefined Length" for VRs that support this
+  according to DICOM PS3.5, even if it does not occur in practice.
+  Affects: dcmdata/libsrc/dcitem.cc
+
+**** Changes from 2025.06.23 (riesmeier)
+
+- Fixed formatting and replaced wrong term.
+  Affects: dcmdata/docs/dcm2json.man
+
+**** Changes from 2025.06.23 (eichelberg)
+
+- Added note on bulk data export.
+  Affects: dcmdata/docs/dcm2json.man
+
+**** Changes from 2025.06.19 (riesmeier)
+
+- Fixed minor issues in manpage:
+  Fixed minor issues in manpage, e.g. capitalization, line breaks,
+  indentation and missing Doxygen markup.
+  Affects: dcmdata/docs/dcm2json.man
+           dcmdata/docs/json2dcm.man
+
+- Fixed indentation of source header.
+  Affects: dcmdata/apps/dcm2json.cc
+
+**** Changes from 2025.06.19 (eichelberg)
+
+- Added a note that json2dcm accepts trailing commas:
+  Added a note to the manual page explaining that json2dcm will accepts
+  some invalid JSON datasets, such as datasets with trailing commas,
+  without error or warning because they are gracefully handled by the
+  underlying JSON parser.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the report.
+  Affects: dcmdata/docs/json2dcm.man
+
+- Fixed generation of 32-bit BMP on Big Endian CPUs:
+  Fixed the conversion of DICOM images to 32-bit BMP files, which worked
+  correctly on Little Endian CPUs but not on Big Endian CPUs.
+  Affects: dcmimage/include/dcmtk/dcmimage/dicopxt.h
+           dcmimgle/libsrc/dimoimg.cc
+
+**** Changes from 2025.06.19 (malaterre)
+
+- Access JSON bulk data URI prefix through API:
+  In DcmJsonFormat::writeBulkData(), access the URI prefix for bulk data
+  URIs through the official API method getBulkDataURIPrefix() in order
+  to allow derived classes to override the implementation.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull request.
+  This closes GitHub PR #121.
+  Affects: dcmdata/libsrc/dcjson.cc
+
+- Reworked JSON writeBulkData API:
+  Now exposing the same set of parameters as the caller function
+  writeBinaryAttribute.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull request.
+  This closes GitHub PR #122.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcjson.h
+           dcmdata/libsrc/dcchrstr.cc
+           dcmdata/libsrc/dcelem.cc
+           dcmdata/libsrc/dcjson.cc
+           dcmdata/libsrc/dcpixel.cc
+           dcmdata/libsrc/dcvrds.cc
+           dcmdata/libsrc/dcvrfd.cc
+           dcmdata/libsrc/dcvrfl.cc
+           dcmdata/libsrc/dcvris.cc
+           dcmdata/libsrc/dcvrsv.cc
+           dcmdata/libsrc/dcvruv.cc
+
+**** Changes from 2025.06.16 (eichelberg)
+
+- Reworded comment on HP color transform:
+  Reworded comment about the non-standard HP color transformation in JPEG-LS.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull request.
+  This closes GitHub PR #119.
+  Affects: dcmjpls/libsrc/djcodece.cc
+
+**** Changes from 2025.06.14 (eichelberg)
+
+- Fixed minor MSVC warning.
+  Affects: dcmdata/apps/json2dcm.cc
+
+**** Changes from 2025.06.13 (xu)
+
+- Changes to JSON2DCM: Moved Exitcodes to JSON2DCM to ensure fixed codes. Removed some DEBUG testing output.
+  Affects: dcmdata/apps/json2dcm.cc
+
+**** Changes from 2025.06.13 (eichelberg)
+
+- Apply bit mask when passing pixel data to CharLS:
+  Apply bit mask when passing pixel data to the CharLS JPEG-LS encoder
+  in "cooked" mode.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the bug report.
+  This closes DCMTK Issue #1160.
+  Affects: dcmjpls/libsrc/djcodece.cc
+
+**** Changes from 2025.06.13 (onken)
+
+- Made destructor virtual:
+  Classes with virtual functions must have their destructor also made
+  virtual.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull
+  request.
+  This closes GitHub pull request #120.
+  Affects: dcmdata/include/dcmtk/dcmdata/libi2d/i2d.h
+
+**** Changes from 2025.06.12 (riesmeier)
+
+- Minor fixes to manpage and syntax usage:
+  Made the description of the tool "json2dcm" more consistent with the
+  one of the pre-existing tool "xml2dcm".
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+- Changed log level and text of some log messages:
+  Changed log level of some log messages and slightly modified the text.
+  Also check the output file for an empty string (similar to "xml2dcm").
+  Affects: dcmdata/apps/json2dcm.cc
+
+- Various minor fixes, mainly related to json2dcm:
+  Various minor fixes that are mainly related to the new command line tool
+  json2dcm. For example, spelling errors, wrong capitalization, unused
+  error and exit codes. Also made the log output more consistent.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+           dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/libsrc/dcchrstr.cc
+           dcmdata/libsrc/dcerror.cc
+           dcmdata/libsrc/dcistrmz.cc
+           dcmdata/libsrc/dcitem.cc
+           dcmdata/libsrc/dcpixel.cc
+           dcmdata/libsrc/dcrleccd.cc
+           dcmdata/libsrc/dcvrds.cc
+           dcmdata/libsrc/dcvris.cc
+
+**** Changes from 2025.06.10 (riesmeier)
+
+- Fixed wrong sub-group title.
+  Affects: dcmdata/docs/json2dcm.man
+
+**** Changes from 2025.06.10 (eichelberg)
+
+- Updated documentation parameter "dcmfile-out":
+  Updated documentation of command line parameter "dcmfile-out",
+  as writing to stdout is supported, but the paramters is not optional
+  anymore. Also fixed minor issues.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+**** Changes from 2025.06.10 (riesmeier)
+
+- Added new command line tool "json2dcm".
+  Affects: .gitignore
+
+- Added "json2dcm" to module's documentation page.
+  Affects: dcmdata/docs/dcmdata.dox
+
+- Updated documentation of parameter "jsonfile-in":
+  Updated documentation of command line parameter "jsonfile-in" as reading
+  from stdin is now also supported. Also fixed various other minor issues
+  related to the documentation.
+  Affects: dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+
+**** Changes from 2025.06.09 (eichelberg)
+
+- Added support for reading from stdin:
+  Added support in json2dcm for reading the JSON file from stdin if the
+  input file name is given as "-". Improved character set related warnings.
+  Affects: dcmdata/apps/json2dcm.cc
+
+**** Changes from 2025.06.07 (eichelberg)
+
+- Fixed memory leaks and segfault in json2dcm:
+  Fixed two memory leaks and a segmentation fault that could occur on some
+  platforms due to a loop reading past the end of an array.
+  Affects: dcmdata/apps/json2dcm.cc
+
+- Replaced C-style casts with C++ casts.
+  Affects: dcmdata/apps/json2dcm.cc
+
+- Fixed URL encoding of path separators.
+  Affects: dcmdata/apps/dcm2json.cc
+
+- Minor fix in jsmn API definition.
+  Affects: ofstd/include/dcmtk/ofstd/ofjsmn.h
+
+**** Changes from 2025.06.06 (eichelberg)
+
+- Fixed shared library build.
+  Affects: ofstd/include/dcmtk/ofstd/ofjsmn.h
+
+**** Changes from 2025.06.06 (xu)
+
+- Initial release of the json2dcm command line tool:
+  Initial release of json2dcm, a tool that converts the contents of a
+  DICOM dataset in JSON encoding to a binary DICOM file or dataset.
+  The JSON document is expected to conform to the "DICOM JSON Model"
+  as defined in DICOM Part 18, Section F. In this initial release,
+  attribute values referenced through BulkDataURIs are not yet supported.
+  Added:   dcmdata/apps/json2dcm.cc
+           dcmdata/docs/json2dcm.man
+  Affects: dcmdata/apps/CMakeLists.txt
+           dcmdata/apps/Makefile.in
+           dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/libsrc/dcerror.cc
+
+- Added JSON parser to module ofstd:
+  Added the "jmsn" header-only JSON parser by Serge Zaitsev to module ofstd.
+  Added:   ofstd/include/dcmtk/ofstd/ofjsmn.h
+           ofstd/libsrc/ofjsmn.cc
+  Affects: COPYRIGHT
+           ofstd/libsrc/CMakeLists.txt
+           ofstd/libsrc/Makefile.in
+
+**** Changes from 2025.06.06 (eichelberg)
+
+- Encode special characters in file: URLs.
+  Affects: dcmdata/apps/dcm2json.cc
+
+**** Changes from 2025.06.05 (riesmeier)
+
+- Enhanced log output for incorrect pixel data:
+  Enhanced log output for incorrectly encoded encapsulated pixel data.
+  In particular, when encapsulated pixel data is encoded with a VR of OW
+  instead of OB, the warning message is now much easier to understand.
+  Affects: dcmdata/libsrc/dcitem.cc
+
+- Made output of warning messages more consistent.
+  Affects: dcmdata/libsrc/dcitem.cc
+
+**** Changes from 2025.06.01 (onken)
+
+- Fixed test failing due to new ftoa implementation:
+  Some months ago DCMTK has introduced a new OFStandard::ftoa
+  implementation() which leads to slightly different floating
+  point numbers when converting from a strings.
+  Affects: dcmfg/tests/t_concatenation_loader.cc
+
+**** Changes from 2025.06.01 (eichelberg)
+
+- Fixed bug in dcm2json:
+  Fixed bug in dcm2json that caused the tool to crash when compiled with STL.
+  Affects: dcmdata/apps/dcm2json.cc
+
+**** Changes from 2025.05.30 (onken)
+
+- Make DCMTK clients build w/o __cplusplus setting:
+  For its internal C++ standard version testing DCMTK sets the __cplusplus
+  macro for Visual Studio since some versions don't set it.
+  However, some external projects that just include the result of this check
+  (which can be found in DCMTK "main" configuration header osconfig.h),
+  might build their code without this flag and fail if osconfig.h still
+  relies on it.
+  The current patch does not change DCMTK's internal version checking but
+  makes sure that once built external projects don't stumble over the
+  __cplusplus macro requirements in osconfig.h. Instead, osconfig.h now
+  checks for _MSVC_LANG (and __cplusplus if that cannot be found).
+  Thanks to Jean-Christophe Fillion-Robins who originally came up with the
+  patch in the the CommonTK (CTK) project.
+  Affects: CMake/osconfig.h.in
+
+**** Changes from 2025.05.28 (riesmeier)
+
+- Added missing GNU Autoconf support to "tests".
+  Affects: dcmtract/tests/Makefile.dep
+           dcmtract/tests/Makefile.in
+
+**** Changes from 2025.05.28 (eichelberg)
+
+- Fixed JSON conversion of compressed images.
+  Affects: dcmdata/libsrc/dcpixel.cc
+
+- Minor fixes in dcm2json.
+  Affects: dcmdata/apps/dcm2json.cc
+           dcmdata/libsrc/dcjson.cc
+
+**** Changes from 2025.05.28 (onken)
+
+- Fixed compiler error/warning in test.
+  Affects: dcmtract/tests/tcreate.cc
+
+**** Changes from 2025.05.27 (onken)
+
+- Fix writing of Tractography Results Series:
+  Fix writing of Tractography Results Series which has been omitted in
+  the past.
+  Also fixed requirement for Referenced Instance Sequence and added
+  debug messages.
+  Added test that demonstrates how to create an Tractography Results
+  object and is helpful to find problems with the code.
+  Thanks to forum user "hapap" for the report.
+  Added:   dcmtract/tests/CMakeLists.txt
+           dcmtract/tests/tcreate.cc
+           dcmtract/tests/tests.cc
+  Affects: dcmtract/CMakeLists.txt
+           dcmtract/include/dcmtk/dcmtract/trctypes.h
+           dcmtract/libsrc/trcmodtractresults.cc
+           dcmtract/libsrc/trctrackset.cc
+           dcmtract/libsrc/trctractographyresults.cc
+           dcmtract/libsrc/trctypes.cc
+
+- Use temp filename.
+  Affects: dcmect/tests/t_overflow.cc
+
+- Added "component" to debug dump.
+  Affects: dcmiod/libsrc/iodrules.cc
+
+**** Changes from 2025.05.27 (eichelberg)
+
+- Fixed compilation of dcm2json on Windows.
+  Affects: dcmdata/apps/dcm2json.cc
+
+**** Changes from 2025.05.23 (eichelberg)
+
+- Added support for BulkDataURI in JSON export:
+  Added support for the generation of BulkDataURIs when exporting DICOM files
+  to JSON in the dcm2json tool. When enabled, bulk data is stored in files
+  that are expected to be accessible through a WADO-RS service. A user-defined
+  URI prefix can be specified for this purpose. Since dcm2json is not a complete
+  DICOMweb implementation, there is no support (yet) for generating MIME multipart
+  structures with bulk data references formatted as a UUID.
+  This closes DCMTK Feature #1151.
+  Affects: dcmdata/apps/dcm2json.cc
+           dcmdata/docs/dcm2json.man
+           dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/include/dcmtk/dcmdata/dcjson.h
+           dcmdata/include/dcmtk/dcmdata/dcpixseq.h
+           dcmdata/include/dcmtk/dcmdata/dcxfer.h
+           dcmdata/libsrc/dcchrstr.cc
+           dcmdata/libsrc/dcelem.cc
+           dcmdata/libsrc/dcerror.cc
+           dcmdata/libsrc/dcjson.cc
+           dcmdata/libsrc/dcpixel.cc
+           dcmdata/libsrc/dcpixseq.cc
+           dcmdata/libsrc/dcvrds.cc
+           dcmdata/libsrc/dcvrfd.cc
+           dcmdata/libsrc/dcvrfl.cc
+           dcmdata/libsrc/dcvris.cc
+           dcmdata/libsrc/dcvrobow.cc
+           dcmdata/libsrc/dcvrod.cc
+           dcmdata/libsrc/dcvrof.cc
+           dcmdata/libsrc/dcvrol.cc
+           dcmdata/libsrc/dcvrov.cc
+           dcmdata/libsrc/dcvrsv.cc
+           dcmdata/libsrc/dcvruv.cc
+           dcmdata/libsrc/dcxfer.cc
+
+**** Changes from 2025.05.14 (eichelberg)
+
+- Fixed linker warning on MacOS.
+  Affects: dcmnet/apps/CMakeLists.txt
+
+- Fixed C++98 build.
+  Affects: dcmdata/libsrc/dcvrobow.cc
+
+**** Changes from 2025.05.09 (eichelberg)
+
+- Added TLS support to movescu:
+  Added TLS support to the movescu tool, both for outgoing
+  and for incoming associations.
+  Affects: dcmnet/apps/CMakeLists.txt
+           dcmnet/apps/Makefile.in
+           dcmnet/apps/movescu.cc
+           dcmnet/docs/movescu.man
+           dcmnet/libsrc/dcmtrans.cc
+
+- Added TLS support for C-MOVE in dcmqrscp:
+  The version of dcmqrscp in DCMTK 3.6.9 had partial support for secure
+  connections in that TLS was supported for incoming associations,
+  but not for outgoing connections. This means that TLS worked for
+  storage, query and retrieve with C-GET, but not with C-MOVE. The
+  TLS support has now be completed to also cover the outgoing
+  associations required for C-MOVE.
+  Affects: dcmqrdb/apps/dcmqrscp.cc
+           dcmqrdb/include/dcmtk/dcmqrdb/dcmqropt.h
+           dcmqrdb/libsrc/dcmqrcbm.cc
+           dcmqrdb/libsrc/dcmqropt.cc
+
+**** Changes from 2025.05.08 (onken)
+
+- Handle NULL values appropriately:
+  The compare methods() in DcmOtherByteOtherWord and DcmPolymorphOBOW did
+  not properly check for NULL values before handing them into memcmp().
+  Affects: dcmdata/include/dcmtk/dcmdata/dcvrobow.h
+           dcmdata/libsrc/dcvrobow.cc
+           dcmdata/libsrc/dcvrpobw.cc
+
+**** Changes from 2025.04.16 (riesmeier)
+
+- Indicated retired attributes in documentation:
+  Made sure that the recently retired EthnicGroup attribute is documented
+  as such, both in header files and man pages.
+  Affects: dcmqrdb/docs/dcmqrscp.man
+           dcmwlm/docs/wlmscpfs.man
+           dcmwlm/include/dcmtk/dcmwlm/wlds.h
+
+- Added support for new DICONDE Storage SOP Class:
+  Added support for the DICONDE Storage SOP Class for ultrasonic waveforms
+  introduced with DICOM 2025b (based on a revised version of ASTM E2663).
+  Affects: dcmdata/include/dcmtk/dcmdata/dcuid.h
+           dcmdata/libsrc/dcuid.cc
+           dcmnet/docs/movescu.man
+           dcmnet/docs/storescp.man
+           dcmnet/etc/storescp.cfg
+           dcmnet/etc/storescu.cfg
+           dcmqrdb/docs/dcmqrscp.man
+           dcmqrdb/etc/dcmqrprf.cfg
+
+- Updated Context Group classes for DICOM 2025b:
+  Updated automatically generated Context Group classes for the latest
+  edition of the DICOM standard. All supported classes were updated,
+  even though there were no changes to most of them.
+  Affects: dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
+           dcmsr/libcmr/cid100.cc
+           dcmsr/libcmr/cid10013.cc
+           dcmsr/libcmr/cid10033.cc
+           dcmsr/libcmr/cid11.cc
+           dcmsr/libcmr/cid218.cc
+           dcmsr/libcmr/cid244.cc
+           dcmsr/libcmr/cid247.cc
+           dcmsr/libcmr/cid29.cc
+           dcmsr/libcmr/cid4020.cc
+           dcmsr/libcmr/cid4021.cc
+           dcmsr/libcmr/cid4031.cc
+           dcmsr/libcmr/cid42.cc
+           dcmsr/libcmr/cid6147.cc
+           dcmsr/libcmr/cid7021.cc
+           dcmsr/libcmr/cid7181.cc
+           dcmsr/libcmr/cid7445.cc
+           dcmsr/libcmr/cid7452.cc
+           dcmsr/libcmr/cid7453.cc
+           dcmsr/libcmr/cid7464.cc
+           dcmsr/libcmr/cid7469.cc
+           dcmsr/libcmr/cid7551.cc
+
+- Updated code definitions for DICOM 2025b:
+  Updated automatically generated code definitions for coding schemes "DCM"
+  and "UMLS". For the coding scheme "NCIt", there were no changes.
+  Affects: dcmsr/include/dcmtk/dcmsr/codes/dcm.h
+           dcmsr/include/dcmtk/dcmsr/codes/ncit.h
+           dcmsr/include/dcmtk/dcmsr/codes/umls.h
+
+- Updated data dictionary for DICOM 2025b:
+  Updated data dictionary for the latest edition of the DICOM standard, which
+  has been released only recently.
+  Since one of the DICOM attributes has been "retired", the name of the
+  associated DcmTagKey constant also changed. This required minor changes to
+  the source code of the dcmiod, dcmqrdb, dcmrt and dcmwlm module.
+  Affects: dcmdata/data/dicom.dic
+           dcmdata/include/dcmtk/dcmdata/dcdeftag.h
+           dcmdata/libsrc/dcdictbi.cc
+           dcmiod/libsrc/modhelp.cc
+           dcmqrdb/libsrc/dcmqrdbi.cc
+           dcmrt/libsrc/drtdose.cc
+           dcmrt/libsrc/drtimage.cc
+           dcmrt/libsrc/drtionpl.cc
+           dcmrt/libsrc/drtiontr.cc
+           dcmrt/libsrc/drtplan.cc
+           dcmrt/libsrc/drtstrct.cc
+           dcmrt/libsrc/drttreat.cc
+           dcmwlm/libsrc/wlds.cc
+
+**** Changes from 2025.04.08 (riesmeier)
+
+- Added note on the potential misuse of options:
+  Added a security note on the potential misuse of options/parameters
+  that can lead to an injection of dangerous content into the HTML/XHTML
+  output.
+  Thanks to drak <dr4k.sec@gmail.com> for the report and proof of concept.
+  Affects: dcmsr/docs/dsr2html.man
+           dcmsr/include/dcmtk/dcmsr/dsrcomvl.h
+           dcmsr/include/dcmtk/dcmsr/dsrdoc.h
+           dcmsr/include/dcmtk/dcmsr/dsrdoctn.h
+           dcmsr/include/dcmtk/dcmsr/dsrdoctr.h
+           dcmsr/include/dcmtk/dcmsr/dsrimgvl.h
+           dcmsr/include/dcmtk/dcmsr/dsrwavvl.h
+
+**** Changes from 2025.04.05 (riesmeier)
+
+- Updated list of multi-frame Storage SOP Classes:
+  Updated the list of multi-frame Storage SOP Classes that is used when
+  generating a DICOMDIR based on an Application Profile that supports
+  MPEG compression.
+  Affects: dcmdata/libsrc/dcddirif.cc
+
+- Added support for new Directory Record Type:
+  Added support for new Waveform Presentation State Directory Record Type
+  "WF PRESENTATION" introduced with Supplement 236, i.e. to the DICOMDIR
+  creating, reading and writing code.
+  This finally closes DCMTK Conformance #1152.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcddirif.h
+           dcmdata/include/dcmtk/dcmdata/dcdirrec.h
+           dcmdata/libsrc/dcddirif.cc
+           dcmdata/libsrc/dcdirrec.cc
+
+**** Changes from 2025.03.24 (eichelberg)
+
+- Disable Borland workarounds when using bcc64x:
+  The Embarcadero bcc64x compiler, a Clang-based 64-bit compiler, does not
+  require or support the workarounds in the DCMTK code implemented once for
+  Borland 5.5. These workarounds are now disabled if bcc64x is detected.
+  Thanks to DCMTK forum user "OliWe" for the suggestion.
+  Affects: CMake/osconfig.h.in
+           dcmdata/libsrc/dcdict.cc
+           oflog/include/dcmtk/oflog/config/win32.h
+           oflog/libsrc/fileap.cc
+           oflog/libsrc/timehelp.cc
+           ofstd/libsrc/ofconsol.cc
+           ofstd/libsrc/ofxml.cc
+
+**** Changes from 2025.03.22 (riesmeier)
+
+- Added quotation marks to CMake variables.
+  Affects: INSTALL
+
+**** Changes from 2025.03.21 (eichelberg)
+
+- Improved description of support lib compile flags:
+  Improved the description of the runtime library selection flags required
+  when compiling the support libraries on Windows.
+  Thanks to DCMTK forum user "pierrechatelier" for the suggestion.
+  Affects: INSTALL
+
+**** Changes from 2025.03.14 (riesmeier)
+
+- Added support for new Presentation States:
+  Added support for new Presentation State SOP Classes introduced with
+  Supplement 236 (Waveform Presentation State) to the DICOM SR module.
+  Affects: dcmsr/include/dcmtk/dcmsr/dsrtypes.h
+           dcmsr/libsrc/dsrtypes.cc
+
+- Added support for new Storage SOP Classes:
+  Added definition of new Storage SOP Class UIDs introduced with Supplement
+  236 (Waveform Presentation State). Also added support for these Storage
+  SOP Classes to the various networking tools.
+  This partly closes DCMTK Conformance #1152.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcuid.h
+           dcmdata/libsrc/dcuid.cc
+           dcmnet/docs/getscu.man
+           dcmnet/docs/movescu.man
+           dcmnet/docs/storescp.man
+           dcmnet/etc/storescp.cfg
+           dcmnet/etc/storescu.cfg
+           dcmqrdb/docs/dcmqrscp.man
+           dcmqrdb/etc/dcmqrprf.cfg
+
+**** Changes from 2025.03.14 (onken)
+
+- Don't check for libsndfile in default build:
+  The public DCMTK does not make any use of libsndfile; therefore there
+  is no need to check for the library at all.
+  For CMake, the library is not checked unless DCMTK_WITH_SNDFILE is
+  enabled by the user.
+  For autoconf, the presence of libsndfile is only checked if
+  configured with --with-libsndfile. Only if found the script will
+  print "checking whether to include libsndfile support...yes" and in
+  all other cases will (default, --without-libsndfile, --with-libsndfile
+  but library not found) print "no" instead.
+  Affects: CMake/dcmtkPrepare.cmake
+           config/configure
+           config/configure.in
+
+**** Changes from 2025.03.08 (eichelberg)
+
+- Removed unused variable.
+  Affects: dcmnet/libsrc/dulfsm.cc
+
+**** Changes from 2025.03.07 (eichelberg)
+
+- Fixed error message on Windows.
+  Affects: dcmnet/libsrc/dulfsm.cc
+
+**** Changes from 2025.03.06 (riesmeier)
+
+- Added initial support for new transfer syntax:
+  Added initial support for the Deflated Image Frame Compression Transfer
+  Syntax that was introduced with Supplement 244.
+  The current support includes reading and writing of DICOM files and
+  data sets that are encoded with this new transfer syntax as well as
+  basic network support (including some of the command line tools).
+  What is still missing is the compression and decompression of this
+  transfer syntax, i.e. the lossless transcoding to/from the various
+  uncompressed transfer syntaxes.
+  This closes DCMTK Conformance #1149.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcuid.h
+           dcmdata/include/dcmtk/dcmdata/dcxfer.h
+           dcmdata/libsrc/dcuid.cc
+           dcmdata/libsrc/dcxfer.cc
+           dcmnet/apps/echoscu.cc
+           dcmnet/apps/movescu.cc
+           dcmnet/apps/storescp.cc
+           dcmnet/docs/echoscu.man
+           dcmnet/docs/movescu.man
+           dcmnet/docs/storescp.man
+           dcmnet/etc/storescp.cfg
+           dcmnet/etc/storescu.cfg
+           dcmnet/libsrc/dimse.cc
+           dcmqrdb/etc/dcmqrprf.cfg
+
+**** Changes from 2025.03.04 (riesmeier)
+
+- Use non-throwing new operator:
+  Use a non-throwing new operator when allocating huge amounts of memory.
+  Affects: dcmimage/include/dcmtk/dcmimage/dicomot.h
+           dcmimgle/include/dcmtk/dcmimgle/dimocpt.h
+           dcmimgle/include/dcmtk/dcmimgle/dimoflt.h
+           dcmimgle/include/dcmtk/dcmimgle/dimorot.h
+           dcmimgle/include/dcmtk/dcmimgle/dimosct.h
+
+- Use non-throwing new operator to avoid crash:
+  Use a non-throwing new operator to avoid a possible crash when allocating
+  huge amounts of memory. Before, an uncatched C++ exception could be thrown
+  when processing an incorrectly encoded DICOM image.
+  Thanks to drak <dr4k.sec@gmail.com> for the report and sample file.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+
+**** Changes from 2025.03.03 (eichelberg)
+
+- Fixed ANNOUNCE.369.
+  Affects: docs/ANNOUNCE.369
+
+- Fixed segfault in JPEG-LS decoder:
+  Fixed a bug in the JPEG-LS decoder that led to a segmentation fault if invalid
+  input data was processed, due to insufficient validation of input data.
+  Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
+  and the sample file (PoC).
+  This closes DCMTK issue #1155.
+  Affects: dcmjpls/libcharls/scan.h
+
+- Fixed bug in RLE decoder:
+  Fixed bug in RLE decoder that caused an application crash when an RLE
+  compressed image with a defective RLE header was processed.
+  Thanks to Simeon Stoykov <simeon@microdicom.com> for the bug report
+  and test file.
+  Affects: dcmdata/libsrc/dcrleccd.cc
+
+**** Changes from 2025.03.02 (riesmeier)
+
+- Always return unknown PDU type with two digits:
+  In case of error, return a status message with two digits (hexadecimal
+  notation) for the unknown PDU type.
+  Affects: dcmnet/libsrc/dulfsm.cc
+
+**** Changes from 2025.02.28 (eichelberg)
+
+- Fixed BMP to DICOM conversion on big-endian CPUs.
+  Affects: dcmdata/apps/img2dcm.cc
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2d.h
+           dcmdata/libi2d/i2d.cc
+
+- Fixed STL file size validation on big-endian CPUs.
+  Affects: dcmdata/libsrc/dcencdoc.cc
+
+**** Changes from 2025.02.27 (riesmeier)
+
+- Added SOP Class to "DICOM Conformance" section:
+  Added Rendition Selection Document Real-Time Communication SOP Class
+  to the list of supported SOP Classes, although it is not a Storage
+  SOP Class but used for Real-Time Communication (see DICOM PS3.22).
+  Affects: dcmsr/docs/dsr2html.man
+           dcmsr/docs/dsr2xml.man
+           dcmsr/docs/dsrdump.man
+           dcmsr/docs/xml2dsr.man
+
+**** Changes from 2025.02.26 (eichelberg)
+
+- Fixed byte order when decoding JPEG-LS on big endian:
+  When running on a big endian architecture, the byte swapping algorithm
+  in the JPEG-LS decoder produced incorrect output when decoding an image
+  with an odd frame size.
+  This closes DCMTK issue #1154.
+  Affects: dcmjpls/include/dcmtk/dcmjpls/djcodecd.h
+           dcmjpls/libsrc/djcodecd.cc
+
+- Warn when decoding frame into odd-length buffer:
+  Print a warning to the logger when decodeFrame() operates on an odd-length
+  frame size on a big endian machine, because in this case the last pixel
+  cannot be corrected for byte order.
+  Affects: dcmdata/libsrc/dcrleccd.cc
+           dcmjpeg/libsrc/djcodecd.cc
+
+**** Changes from 2025.02.24 (riesmeier)
+
+- Updated Context Group classes for DICOM 2025a:
+  Updated automatically generated Context Group classes for the latest
+  edition of the DICOM standard. All supported classes were updated,
+  even though there were no changes to most of them.
+  Affects: dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
+           dcmsr/libcmr/cid100.cc
+           dcmsr/libcmr/cid10013.cc
+           dcmsr/libcmr/cid10033.cc
+           dcmsr/libcmr/cid11.cc
+           dcmsr/libcmr/cid218.cc
+           dcmsr/libcmr/cid244.cc
+           dcmsr/libcmr/cid247.cc
+           dcmsr/libcmr/cid29.cc
+           dcmsr/libcmr/cid4020.cc
+           dcmsr/libcmr/cid4021.cc
+           dcmsr/libcmr/cid4031.cc
+           dcmsr/libcmr/cid42.cc
+           dcmsr/libcmr/cid6147.cc
+           dcmsr/libcmr/cid7021.cc
+           dcmsr/libcmr/cid7181.cc
+           dcmsr/libcmr/cid7445.cc
+           dcmsr/libcmr/cid7452.cc
+           dcmsr/libcmr/cid7453.cc
+           dcmsr/libcmr/cid7464.cc
+           dcmsr/libcmr/cid7469.cc
+           dcmsr/libcmr/cid7551.cc
+
+- Updated code definitions for DICOM 2025a:
+  Updated automatically generated code definitions for coding scheme "NCIt".
+  For the coding schemes "DCM" and "UMLS", there were no changes.
+  Affects: dcmsr/include/dcmtk/dcmsr/codes/dcm.h
+           dcmsr/include/dcmtk/dcmsr/codes/ncit.h
+           dcmsr/include/dcmtk/dcmsr/codes/umls.h
+
+- Updated data dictionary for DICOM 2025a:
+  Updated data dictionary for the latest edition of the DICOM standard.
+  Affects: dcmdata/data/dicom.dic
+           dcmdata/include/dcmtk/dcmdata/dcdeftag.h
+           dcmdata/libsrc/dcdictbi.cc
+
+**** Changes from 2025.02.23 (eichelberg)
+
+- Fixed Solaris/OpenIndiana build.
+  Affects: dcmdata/libsrc/dcvrod.cc
+           dcmdata/libsrc/dcvrof.cc
+
+**** Changes from 2025.02.21 (riesmeier)
+
+- Avoid possible output of "-nan" in XML format:
+  Avoid possible output of "-nan" in XML format in order to be consistent
+  throughout the toolkit and to avoid problems when reading such data.
+  This closes DCMTK Bug #1153.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the report
+  and sample instructions to reproduce this issue.
+  Affects: dcmdata/libsrc/dcvrod.cc
+           dcmdata/libsrc/dcvrof.cc
+           dcmsr/libsrc/dsrnumvl.cc
+
+- Made sure float/double values use a decimal point:
+  Made sure that floating point and double values use a proper decimal
+  point when output to a C++ stream. This requires to explicitly set the
+  "C" locale in case the user changed the default, i.e. the global locale.
+  This partly closes DCMTK Bug #1153.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the report
+  on a related issue (that is not yet fixed).
+  Affects: dcmdata/libsrc/dcvrod.cc
+           dcmdata/libsrc/dcvrof.cc
+           dcmimgle/libsrc/dicielut.cc
+           dcmimgle/libsrc/digsdlut.cc
+           dcmsr/libsrc/dsrnumvl.cc
+
+**** Changes from 2025.02.21 (eichelberg)
+
+- Added support for "-nan" in OFStandard::atof():
+  OFStandard::atof() will now accept "-nan" as a valid string
+  and convert it to a quiet NaN.
+  Affects: ofstd/libsrc/ofstd.cc
+
+- Updated some comments.
+  Affects: ofstd/libsrc/ofstd.cc
+
+**** Changes from 2025.02.21 (riesmeier)
+
+- Report warning on incorrect Mapping Resource UID:
+  Output a warning message when reading the UID that is defined for the
+  DICOM Content Mapping Resource (DCMR) for a different Mapping Resource.
+  Also tried to harmonized capitalization of DICOM names in comments.
+  Affects: dcmsr/libsrc/dsrdoctn.cc
+
+**** Changes from 2025.02.20 (riesmeier)
+
+- Report warning on unexpected Verifying Observers:
+  Output a warning message when reading Verifying Observer(s) from a
+  document (DICOM or XML) that has a Verification Flag of "UNVERIFIED".
+  Affects: dcmsr/libsrc/dsrdoc.cc
+
+**** Changes from 2025.02.20 (eichelberg)
+
+- Fixed minor inconsistency in macro definition.
+  Affects: ofstd/libsrc/ofstd.cc
+
+**** Changes from 2025.02.20 (riesmeier)
+
+- Increased precision of float/double output to XML:
+  Increased precision of float output to 9 and double to 17 in order to be
+  "lossless" when writing/reading to/from XML format.
+  Affects: dcmdata/libsrc/dcvrof.cc
+           dcmsr/libsrc/dsrnumvl.cc
+
+**** Changes from 2025.02.20 (eichelberg)
+
+- Refuse compilation on platforms without 64-bit int:
+  Refuse compilation on platforms where no 64-bit integers are available.
+  This is necessary since the Uint64/Sint64 typedefs are meanwhile used in
+  various places in the toolkit.
+  Affects: ofstd/include/dcmtk/ofstd/offile.h
+           ofstd/include/dcmtk/ofstd/ofrand.h
+           ofstd/include/dcmtk/ofstd/oftypes.h
+           ofstd/libsrc/ofrand.cc
+
+**** Changes from 2025.02.19 (riesmeier)
+
+- Fixed wrong Doxygen subsection labels.
+  Affects: dcmdata/docs/dcm2pdf.man
+
+- Used "@note" in Doxgen's API documentation:
+  Used "@note" command in Doxygen's API documentation to highlight when
+  certain methods are only applicable to particular VRs.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcitem.h
+
+- Added putAndInsertXXX() methods for 64-bit VRs:
+  Added helper methods putAndInsertUint64(), putAndInsertUint64Array(),
+  putAndInsertSint64() and putAndInsertSint64Array() for the still
+  rather new 64-bit VRs "SV", "UV" and "OV".
+  Affects: dcmdata/include/dcmtk/dcmdata/dcitem.h
+           dcmdata/libsrc/dcitem.cc
+
+- Added missing virtual functions to base class:
+  Added missing virtual functions putUint64(), putSint64(), putUint64Array()
+  and putSint64Array() to the DcmElement class. Apparently, they were
+  forgotten when support for the 64-bit VRs "SV", "UV" and "OV" was added
+  some years ago.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the report.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcelem.h
+           dcmdata/libsrc/dcelem.cc
+
+**** Changes from 2025.02.17 (malaterre)
+
+- Provide a hook to setup iconv path at runtime:
+  Provide a new function OFiconv_setpath() that allows an application
+  to change the iconv data path at runtime. Note: the DCMICONVPATH
+  environment variable will override any path set with this function.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the pull request.
+  This closes GitHub PR #116.
+  Affects: oficonv/include/dcmtk/oficonv/iconv.h
+           oficonv/libsrc/citrus_bcs.c
+           oficonv/libsrc/oficonv_iconv.c
+
+**** Changes from 2025.02.12 (riesmeier)
+
+- Fixed issue with icon image of IMAGE content item:
+  Fixed issue with the optional icon image of an IMAGE content item that
+  was not copied when the setValue() method was called. Depending on how
+  the underlying DSRImageReferenceValue class was used, this resulted in
+  the Icon Image Sequence (0088,0200) missing in the created DICOM dataset.
+  Also added new regression tests that make sure that the icon image is
+  created correctly and copied when needed.
+  Thanks to forum user "pintagliata" for the original report.
+  Added:   dcmsr/tests/tsrimgvl.cc
+  Affects: dcmsr/include/dcmtk/dcmsr/dsrimgvl.h
+           dcmsr/libsrc/dsrimgvl.cc
+           dcmsr/tests/CMakeLists.txt
+           dcmsr/tests/Makefile.dep
+           dcmsr/tests/Makefile.in
+           dcmsr/tests/tests.cc
+
+**** Changes from 2025.02.11 (riesmeier)
+
+- Added "datadir" and "docdir" to CMake config:
+  Added CMake variables CMAKE_INSTALL_DATADIR and CMAKE_INSTALL_DOCDIR
+  to the DCMTK configuration that is exported to "DCMTKConfig.cmake".
+  This is particularly important as both paths usually contain the DCMTK
+  version number, which might not be known to the project that imports
+  the DCMTK configuration.
+  Also added quotation marks to all exported installation subdirectories
+  so that spaces and other "special" characters are supported.
+  Affects: CMake/DCMTKConfig.cmake.in
+
+**** Changes from 2025.02.11 (eichelberg)
+
+- Fixed precision when converting double to text:
+  Fixed a bug in OFStandard::ftoa() that caused floating point numbers
+  to be converted/printed with less precision than requested.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the
+  bug report and test file.
+  Affects: ofstd/libsrc/ofstd.cc
+
+**** Changes from 2025.02.11 (riesmeier)
+
+- Fixed calculation of no. of TLS 1.3 cipher suites:
+  Fixed wrong calculation of number of TLS 1.3 cipher suites.
+  Thanks to forum user "Shaeto" for the report.
+  Affects: dcmtls/libsrc/tlsciphr.cc
+
+**** Changes from 2025.02.07 (eichelberg)
+
+- Removed conditional code for very old MSVC versions:
+  Removed conditionally compiled code for very old MSVC versions
+  (Visual Studio 2010 and older) that are not supported anymore,
+  in order to reduce the amount of dead code in the toolkit.
+  Affects: CMake/osconfig.h.in
+           dcmdata/tests/tfilter.cc
+           dcmjpls/libcharls/lltraits.h
+           oflog/include/dcmtk/oflog/config.h
+           oflog/include/dcmtk/oflog/config/win32.h
+           oflog/libsrc/log4judp.cc
+           oflog/libsrc/threads.cc
+           oflog/libsrc/timehelp.cc
+           ofstd/include/dcmtk/ofstd/ofcmdln.h
+           ofstd/include/dcmtk/ofstd/ofmem.h
+           ofstd/include/dcmtk/ofstd/ofoption.h
+
+**** Changes from 2025.02.07 (riesmeier)
+
+- Replaced spaces by tab character for indendation.
+  Affects: ofstd/libsrc/Makefile.in
+
+- Added line break for 80-characters-per-line limit.
+  Affects: dcmpstat/docs/dcmprscp.man
+           dcmpstat/docs/dcmprscu.man
+
+- Added missing newline to "FILES" section.
+  Affects: dcmsr/docs/dsr2html.man
+
+**** Changes from 2025.02.07 (eichelberg)
+
+- Added class that computes SHA-256 checksums:
+  Added a class in ofstd that computes SHA-256 checksums and does not depend
+  on OpenSSL. The code is based on the SHA-256 implementation by
+  Brad Conte (brad AT bradconte.com) in FreeBSD.
+  Added:   ofstd/include/dcmtk/ofstd/ofsha256.h
+           ofstd/libsrc/ofsha256.cc
+  Affects: ofstd/libsrc/CMakeLists.txt
+           ofstd/libsrc/Makefile.in
+
+**** Changes from 2025.02.06 (riesmeier)
+
+- Fixed source code formatting.
+  Affects: dcmdata/libsrc/dcjson.cc
+
+**** Changes from 2025.02.05 (riesmeier)
+
+- Fixed minor documentation errors:
+  Fixed wrong struct name in documentation sample code. Also fixed various
+  other minor issues in API documentation and comments.
+  Thanks to GitHub user "malaterre" the original report and proposed patch.
+  This closes GitHub pull request #115.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcjson.h
+           dcmdata/libsrc/dcjson.cc
+
+- Reverted accidentally committed changes:
+  Reverted changes that were accidentally committed with commit 9a0189b5a.
+  Instead, added a comment that there is still a TODO for handling incoming
+  C-ECHO requests.
+  Affects: dcmnet/libsrc/dstorscp.cc
+
+- Removed space between CMake command and "(".
+  Affects: CMake/3rdparty.cmake
+           CMake/GenerateDCMTKConfigure.cmake
+           CMake/dcmtkPrepare.cmake
+
+**** Changes from 2025.02.04 (riesmeier)
+
+- Added the usual note for development versions.
+  Affects: INSTALL
+           dcmnet/libsrc/dstorscp.cc
+
+**** Changes from 2025.02.04 (eichelberg)
+
+- Silently remove trailing zero bytes in strings:
+  Silently remove trailing zero bytes in character string VRs
+  if dcmEnableAutomaticInputDataCorrection is enabled.
+  This closes DCMTK issue #1014.
+  Affects: dcmdata/libsrc/dcbytstr.cc
+
+- Updated INSTALL for previous commit.
+  Affects: INSTALL
+
+- Stop cmake with error message if C++ standard is 98:
+  Stop with an error message if somebody tries to compile DCMTK with a compiler
+  that either does not support C++11, or is configured via CMAKE_CXX_STANDARD
+  to only use C++98. For now, compilation with C++98 can be enabled be running
+  cmake -DDCMTK_PERMIT_CXX98=ON, but this will not work anymore in future
+  DCMTK releases.
+  Affects: CMake/GenerateDCMTKConfigure.cmake
+           CMake/dcmtkPrepare.cmake
+
+**** Changes from 2025.01.30 (eichelberg)
+
+- Fixed minor warnings.
+  Affects: dcmdata/libi2d/i2djpgs.cc
+           dcmdata/libi2d/i2dplnsc.cc
+           dcmdata/libi2d/i2dplop.cc
+           dcmdata/libi2d/i2dplvlp.cc
+
+**** Changes from 2025.01.29 (eichelberg)
+
+- Improved handling of JPEG image files:
+  Improved the handling of JPEG image files as input to img2dcm. Several special
+  cases such as different types of component subsampling, as well as lossy
+  JPEG images  in RGB or CMYK color (instead of YCbCr) are now correctly
+  handled, and rejected if necessary.
+  This closes DCMTK issue #995.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the suggestion.
+  Affects: dcmdata/include/dcmtk/dcmdata/libi2d/i2d.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2djpgs.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2doutpl.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2dplnsc.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2dplop.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2dplsc.h
+           dcmdata/include/dcmtk/dcmdata/libi2d/i2dplvlp.h
+           dcmdata/libi2d/i2d.cc
+           dcmdata/libi2d/i2djpgs.cc
+           dcmdata/libi2d/i2dplnsc.cc
+           dcmdata/libi2d/i2dplop.cc
+           dcmdata/libi2d/i2dplsc.cc
+           dcmdata/libi2d/i2dplvlp.cc
+
+**** Changes from 2025.01.28 (riesmeier)
+
+- Avoid warning on unused variable:
+  Avoid warning on unused variable when compiled without character set
+  conversion support.
+  Affects: dcmsr/apps/dsr2html.cc
+           dcmsr/apps/dsrdump.cc
+
+**** Changes from 2025.01.25 (riesmeier)
+
+- Added support for the Context Group Keyword:
+  Added support for the official Context Group Keyword that was introduced
+  for all Context Groups of the DICOM Content Mapping Resource (DCMR, see
+  DICOM PS3.16) with CP-2181.
+  This change required to regenerate all automatically generated Context
+  Group classes (still based on DICOM 2024e).
+  This closes DCMTK Feature #1033.
+  Affects: dcmsr/include/dcmtk/dcmsr/cmr/cid100.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10013.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid10033.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid11.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid218.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid244.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid247.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid29.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4020.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid4031.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid42.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid6147.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7021.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7181.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7445.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7452.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7453.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7464.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7469.h
+           dcmsr/include/dcmtk/dcmsr/cmr/cid7551.h
+           dcmsr/include/dcmtk/dcmsr/dsrctxgr.h
+           dcmsr/libcmr/cid100.cc
+           dcmsr/libcmr/cid10013.cc
+           dcmsr/libcmr/cid10033.cc
+           dcmsr/libcmr/cid11.cc
+           dcmsr/libcmr/cid218.cc
+           dcmsr/libcmr/cid244.cc
+           dcmsr/libcmr/cid247.cc
+           dcmsr/libcmr/cid29.cc
+           dcmsr/libcmr/cid4020.cc
+           dcmsr/libcmr/cid4021.cc
+           dcmsr/libcmr/cid4031.cc
+           dcmsr/libcmr/cid42.cc
+           dcmsr/libcmr/cid5000.cc
+           dcmsr/libcmr/cid5001.cc
+           dcmsr/libcmr/cid6147.cc
+           dcmsr/libcmr/cid7021.cc
+           dcmsr/libcmr/cid7181.cc
+           dcmsr/libcmr/cid7445.cc
+           dcmsr/libcmr/cid7452.cc
+           dcmsr/libcmr/cid7453.cc
+           dcmsr/libcmr/cid7464.cc
+           dcmsr/libcmr/cid7469.cc
+           dcmsr/libcmr/cid7551.cc
+           dcmsr/libsrc/dsrctxgr.cc
+           dcmsr/tests/tsrcmr.cc
+
+**** Changes from 2025.01.24 (eichelberg)
+
+- Improved diagnostic log output.
+  Affects: dcmdata/libsrc/dcrleccd.cc
+
+**** Changes from 2025.01.23 (eichelberg)
+
+- Fixed issue with invalid RLE compressed DICOM images:
+  Fixed issue when processing an RLE compressed image where the RLE header
+  contains an invalid stripe size.
+  Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
+  and the sample file (PoC).
+  Affects: dcmdata/libsrc/dcrleccd.cc
+
+**** Changes from 2025.01.22 (eichelberg)
+
+- Fixed access rights.
+  Affects: docs/ANNOUNCE.369
+
+**** Changes from 2025.01.21 (riesmeier)
+
+- Made sure all member variables are initialized:
+  Initialized member variable that was missing in the member initializer
+  list of the constructor. This issue was reported at runtime when compiling
+  with gcc and option -fsanitize=undefined.
+  Affects: dcmiod/libsrc/modmultiframedimension.cc
+
+- Fixed another issue with invalid DICOM images:
+  Fixed issue when processing an invalid DICOM image where the number of
+  pixels stored does not match the expected number of pixels (too less)
+  and the combination of BitsAllocated and BitsStored is really unusual
+  (e.g. 1 bit stored, but 52 bits allocated). In cases where the last
+  pixel (e.g. a single bit) does not fit into the buffer of the input
+  pixel data, a buffer overflow occurred on the heap. Now, the last entry
+  of the buffer is filled with the smallest possible value (e.g. 0 in case
+  of unsigned data).
+  Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
+  and the sample file (PoC).
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+
+- Don't call getAbsMinimum() in a for-loop:
+  Use a local constant instead of calling getAbsMinimum() in a for-loop,
+  even if it is probably expanded as an inline function.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+
+**** Changes from 2025.01.20 (riesmeier)
+
+- Removed further outdated Autoconf tests:
+  See commits 09017a3cb and 95c799f57 for details and the corresponding
+  CMake changes.
+  Affects: config/aclocal.m4
+           config/configure
+           config/configure.in
+           config/confmod
+           config/include/dcmtk/config/osconfig.h.in
+
+**** Changes from 2025.01.20 (eichelberg)
+
+- Further clean-up of outdated configure tests.
+  Affects: CMake/GenerateDCMTKConfigure.cmake
+           CMake/osconfig.h.in
+
+**** Changes from 2025.01.19 (eichelberg)
+
+- Fixed character set conversion in dcm2json:
+  Fixed character set conversion in dcm2json for the case that an extended
+  character set is used but that character set that does not contain byte
+  positions > 127 (such as ISO_IR 87) and is thus not detected by
+  DcmItem::containsExtendedCharacters().
+  Affects: dcmdata/apps/dcm2json.cc
+
+- Fixed debug build on Win32.
+  Affects: dcmdata/libsrc/dcistrmz.cc
+
+**** Changes from 2025.01.18 (eichelberg)
+
+- Further clean-up of outdated configure tests:
+  Cleaned up configure tests that checked for features that are not used
+  in DCMTK anymore or that are not in use anymore on any of the supported
+  operating systems (e.g. pre-POSIX APIs and header files).
+  Affects: CMake/GenerateDCMTKConfigure.cmake
+           CMake/osconfig.h.in
+           config/docs/macros.txt
+           config/math.cc
+           dcmapps/include/dcmtk/dcmapps/dcm2img.h
+           dcmdata/apps/dcm2pdf.cc
+           dcmdata/apps/dump2dcm.cc
+           dcmdata/include/dcmtk/dcmdata/dctypes.h
+           dcmdata/libdcxml/xml2dcm.cc
+           dcmdata/libsrc/cmdlnarg.cc
+           dcmdata/libsrc/dcbytstr.cc
+           dcmdata/libsrc/dcelem.cc
+           dcmdata/libsrc/dcistrmf.cc
+           dcmdata/libsrc/dcistrms.cc
+           dcmdata/libsrc/dcostrmf.cc
+           dcmdata/libsrc/dcostrms.cc
+           dcmdata/libsrc/dcuid.cc
+           dcmimage/include/dcmtk/dcmimage/dicopxt.h
+           dcmimage/include/dcmtk/dcmimage/diqtpbox.h
+           dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+           dcmimgle/include/dcmtk/dcmimgle/dimopxt.h
+           dcmjpeg/libijg12/jconfig12.h
+           dcmjpeg/libijg12/jerror.c
+           dcmjpeg/libijg16/jconfig16.h
+           dcmjpeg/libijg16/jerror.c
+           dcmjpeg/libijg8/jconfig8.h
+           dcmjpeg/libijg8/jerror.c
+           dcmjpls/libcharls/encodstr.h
+           dcmjpls/libcharls/streams.h
+           dcmjpls/libsrc/djcodece.cc
+           dcmnet/apps/storescp.cc
+           dcmnet/include/dcmtk/dcmnet/dcompat.h
+           dcmnet/libsrc/assoc.cc
+           dcmnet/libsrc/dcmtrans.cc
+           dcmnet/libsrc/dcompat.cc
+           dcmnet/libsrc/dimcancl.cc
+           dcmnet/libsrc/dimcmd.cc
+           dcmnet/libsrc/dimdump.cc
+           dcmnet/libsrc/dimfind.cc
+           dcmnet/libsrc/dimget.cc
+           dcmnet/libsrc/dimmove.cc
+           dcmnet/libsrc/dimse.cc
+           dcmnet/libsrc/dimstore.cc
+           dcmnet/libsrc/diutil.cc
+           dcmnet/libsrc/dul.cc
+           dcmnet/libsrc/dulextra.cc
+           dcmnet/libsrc/dulfsm.cc
+           dcmpstat/apps/dcmprscp.cc
+           dcmpstat/apps/dcmprscu.cc
+           dcmpstat/apps/dcmpsrcv.cc
+           dcmpstat/apps/dcmpssnd.cc
+           dcmpstat/libsrc/dviface.cc
+           dcmpstat/libsrc/dvpshlp.cc
+           dcmpstat/tests/msgserv.cc
+           dcmqrdb/apps/dcmqrscp.cc
+           dcmqrdb/libsrc/dcmqrcbg.cc
+           dcmqrdb/libsrc/dcmqrcbm.cc
+           dcmqrdb/libsrc/dcmqrcnf.cc
+           dcmqrdb/libsrc/dcmqrdbi.cc
+           dcmqrdb/libsrc/dcmqrtis.cc
+           dcmsr/libsrc/dsrxmld.cc
+           dcmtls/libsrc/tlstrans.cc
+           dcmwlm/libsrc/wldsfs.cc
+           oficonv/apps/mkcsmapper.y
+           oficonv/apps/mkcsmapper_bison.cc
+           oficonv/apps/mkcsmapper_bison.h
+           oficonv/apps/mkesdb.y
+           oficonv/apps/mkesdb_bison.cc
+           oficonv/apps/mkesdb_bison.h
+           oficonv/include/dcmtk/oficonv/iconv.h
+           oficonv/libsrc/citrus_bcs.h
+           oficonv/libsrc/citrus_big5.c
+           oficonv/libsrc/citrus_csmapper.c
+           oficonv/libsrc/citrus_db.c
+           oficonv/libsrc/citrus_db_factory.c
+           oficonv/libsrc/citrus_db_hash.c
+           oficonv/libsrc/citrus_dechanyu.c
+           oficonv/libsrc/citrus_esdb.c
+           oficonv/libsrc/citrus_euc.c
+           oficonv/libsrc/citrus_euctw.c
+           oficonv/libsrc/citrus_gbk2k.c
+           oficonv/libsrc/citrus_hash.c
+           oficonv/libsrc/citrus_hz.c
+           oficonv/libsrc/citrus_iconv.c
+           oficonv/libsrc/citrus_iso2022.c
+           oficonv/libsrc/citrus_jisx0208.c
+           oficonv/libsrc/citrus_johab.c
+           oficonv/libsrc/citrus_lookup.c
+           oficonv/libsrc/citrus_mapper.c
+           oficonv/libsrc/citrus_mmap.c
+           oficonv/libsrc/citrus_module.c
+           oficonv/libsrc/citrus_mskanji.c
+           oficonv/libsrc/citrus_none.c
+           oficonv/libsrc/citrus_region.h
+           oficonv/libsrc/citrus_types.h
+           oficonv/libsrc/citrus_utf1632.c
+           oficonv/libsrc/citrus_utf8.c
+           oficonv/libsrc/citrus_viqr.c
+           oficonv/libsrc/citrus_zw.c
+           oficonv/libsrc/oficonv_iconv.c
+           oflog/include/dcmtk/oflog/config/defines.h
+           ofstd/include/dcmtk/ofstd/ofdate.h
+           ofstd/include/dcmtk/ofstd/offile.h
+           ofstd/include/dcmtk/ofstd/oflist.h
+           ofstd/include/dcmtk/ofstd/ofsockad.h
+           ofstd/include/dcmtk/ofstd/ofstd.h
+           ofstd/include/dcmtk/ofstd/ofstdinc.h
+           ofstd/include/dcmtk/ofstd/ofstream.h
+           ofstd/include/dcmtk/ofstd/oftempf.h
+           ofstd/include/dcmtk/ofstd/oftime.h
+           ofstd/include/dcmtk/ofstd/oftypes.h
+           ofstd/include/dcmtk/ofstd/ofvector.h
+           ofstd/libsrc/ofconsol.cc
+           ofstd/libsrc/ofdatime.cc
+           ofstd/libsrc/offilsys.cc
+           ofstd/libsrc/offname.cc
+           ofstd/libsrc/ofipc.cc
+           ofstd/libsrc/ofstd.cc
+
+**** Changes from 2025.01.17 (riesmeier)
+
+- Fixed another issue with invalid mono images:
+  Fixed issue when rendering an invalid monochrome DICOM image where the
+  number of pixels stored does not match the expected number of pixels.
+  In this case, only a single pixel is processed, but the pixel matrix is
+  much larger. Filling the rest of the pixel matrix with the smallest
+  possible value for the image is not working because of an optimized
+  memory usage (value would be out of range). Now, the pixel value to be
+  used is double-checked before it is actually filled into the "background"
+  of the image.
+  Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
+  and the sample file (PoC).
+  Affects: dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+
+- Made sure that memory is always cleaned up:
+  Made sure that allocated memory is always cleaned up, i.e. also in case
+  of error. Otherwise, tools like ASAN will report memory leaks.
+  Affects: dcmapps/include/dcmtk/dcmapps/dcm2img.h
+
+- Do not exceed the maximum size of DcmList:
+  Made sure that the maximum number of entries of an DcmList instance is
+  not exceeded. Even if it is unlikely, NULL is returned and a message is
+  output to the debug logger.
+  Affects: dcmdata/include/dcmtk/dcmdata/dclist.h
+           dcmdata/libsrc/dclist.cc
+
+- Further optimizations of DcmList:seek_to():
+  Handle the special cases seek_to() first and last item in the list more
+  efficiently. Also avoid unnecessary call of DcmList::get() in case of an
+  invalid position.
+  Affects: dcmdata/libsrc/dclist.cc
+
+- Replaced call of DcmList::seek_to() by seek():
+  Replaced call of DcmList::seek_to() by seek() for accessing the first
+  and the last item of the list. This should slightly improve the
+  performance when DcmFileFormat::getMetaInfo() or getDataset() are called
+  many times.
+  Affects: dcmdata/libsrc/dcfilefo.cc
+
+- Improved performance of DcmList::seek_to():
+  Significantly improved the performance of the seek_to() method, in
+  particular when iterating a very long list using the position of the
+  items, e.g. a DcmPixelSequence with a huge number of instances of
+  DcmPixelItem such as in Whole Slide Imaging (WSI) objects. Internally,
+  the seek_to() method is, e.g., used in the insert(), remove() and
+  getItem() methods of DcmSequenceOfItems and DcmPixelSequence as well
+  as in the getElement() and remove() method of DcmItem.
+  Thanks to GitHub user "reunanen" for the report and proposed patch.
+  This closes GitHub pull request #114.
+  Affects: dcmdata/include/dcmtk/dcmdata/dclist.h
+           dcmdata/libsrc/dclist.cc
+           dcmdata/tests/tsequen.cc
+
+**** Changes from 2025.01.17 (eichelberg)
+
+- Fixed handling of SpecificCharacterSet in sequences:
+  Fixed the handling of files where SpecificCharacterSet may occur
+  in sequence items and where different items might use different
+  character sets, such as DICOMDIRs.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com>
+  for pointing out the issue.
+  Affects: dcmdata/apps/dcm2json.cc
+
+**** Changes from 2025.01.15 (riesmeier)
+
+- Made a minor change to the API documentation.
+  Affects: dcmsr/include/dcmtk/dcmsr/dsrdoc.h
+
+**** Changes from 2025.01.14 (riesmeier)
+
+- Restructured code of method convertString():
+  Restructured code of the convertString() method by splitting it into two
+  methods: one for strings without and one for strings with code extension
+  techniques according to ISO 2022. This should increase the readability
+  of the code.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcspchrs.h
+           dcmdata/libsrc/dcspchrs.cc
+
+**** Changes from 2025.01.13 (eichelberg)
+
+- Fixed HAVE_PROTOTYPE_FEENABLEEXCEPT configure test.
+  Affects: CMake/GenerateDCMTKConfigure.cmake
+
+- Fixed a few memory leaks in unit tests.
+  Affects: dcmdata/tests/tfrmsiz.cc
+           dcmect/tests/t_overflow.cc
+           dcmfg/tests/t_fg_base.cc
+           dcmseg/tests/tutils.cc
+
+- Fixed two memory leaks in oficonv.
+  Affects: oficonv/include/dcmtk/oficonv/iconv.h
+           oficonv/libsrc/citrus_iconv.c
+           oficonv/libsrc/citrus_iconv.h
+           oficonv/libsrc/citrus_mapper_zone.c
+           oficonv/libsrc/oficonv_iconv.c
+           oficonv/tests/tests.cc
+           oficonv/tests/ticonv.cc
+
+**** Changes from 2025.01.13 (riesmeier)
+
+- Enhanced dcm2xml's support for DICOMDIR files:
+  Fixed conversion of DICOMDIR files to UTF-8 encoding (i.e. when using
+  option +U8) by removing an irritating error message and making sure
+  that no SpecificCharacterSet element is added to the top-level dataset.
+  Affects: dcmdata/apps/dcm2xml.cc
+
+**** Changes from 2025.01.11 (riesmeier)
+
+- Fixed issue rendering invalid monochrome image:
+  Fixed issue when rendering an invalid monochrome DICOM image where the
+  number of pixels stored does not match the expected number of pixels.
+  If the stored number is less than the expected number, the rest of the
+  pixel matrix for the intermediate representation was always filled with
+  the value 0. Under certain, very rare conditions, this could result in
+  memory problems reported by an Address Sanitizer (ASAN). Now, the rest
+  of the matrix is filled with the smallest possible value for the image.
+  Thanks to Emmanuel Tacheau from the Cisco Talos team
+  <vulndiscovery@external.cisco.com> for the original report, the sample
+  file (PoC) and further details. See TALOS-2024-2122 and CVE-2024-47796.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+
+- Enhanced check for invalid NULL parameter:
+  Even if the passed value should never be NULL, such a check does not
+  do any harm.
+  Affects: dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+
+- Replaced call of delete by delete[]:
+  This issue has been reported by the gcc address sanitizer (using option
+  -fsanitize=address).
+  Affects: dcmimgle/libsrc/diimage.cc
+
+**** Changes from 2025.01.10 (riesmeier)
+
+- Fixed issue with Doxygen grouping markup:
+  Fixed issue with grouping markup when using newer Doxygen versions.
+  Affects: dcmdata/include/dcmtk/dcmdata/dcbytstr.h
+           dcmdata/include/dcmtk/dcmdata/dcerror.h
+           dcmdata/include/dcmtk/dcmdata/dctypes.h
+           dcmimgle/include/dcmtk/dcmimgle/diutils.h
+           dcmrt/include/dcmtk/dcmrt/drttypes.h
+           dcmseg/include/dcmtk/dcmseg/segtypes.h
+           dcmsr/include/dcmtk/dcmsr/cmr/tid1500.h
+           dcmsr/include/dcmtk/dcmsr/cmr/tid15def.h
+           dcmsr/include/dcmtk/dcmsr/cmr/tid1600.h
+           dcmsr/include/dcmtk/dcmsr/dsrtypes.h
+           ofstd/include/dcmtk/ofstd/ofchrenc.h
+           ofstd/include/dcmtk/ofstd/ofcond.h
+           ofstd/include/dcmtk/ofstd/ofstd.h
+           ofstd/include/dcmtk/ofstd/oftest.h
+
+**** Changes from 2025.01.06 (eichelberg)
+
+- Fixed minor warning on MSVC.
+  Affects: ofstd/tests/tstring.cc
+
+**** Changes from 2025.01.05 (riesmeier)
+
+- Fixed wrong capitalization of acronym "JSON".
+  Affects: dcmdata/libsrc/dcjson.cc
+           dcmdata/libsrc/dcvrds.cc
+           dcmdata/libsrc/dcvris.cc
+
+**** Changes from 2025.01.05 (eichelberg)
+
+- Added OFString/std::string conversion helpers:
+  Added helper functions to convert between std::string and OFString.
+  This closes DCMTK feature #1106.
+  Added:   ofstd/include/dcmtk/ofstd/ofstrhlp.h
+  Affects: ofstd/tests/tests.cc
+           ofstd/tests/tstring.cc
+
+**** Changes from 2025.01.04 (eichelberg)
+
+- Added logger warnings when converting invalid IS/DS:
+  Added logger warnings when converting invalid IS/DS values to Json.
+  This closes DCMTK Feature #1084.
+  Affects: dcmdata/libsrc/dcvrds.cc
+           dcmdata/libsrc/dcvris.cc
+
+**** Changes from 2025.01.03 (riesmeier)
+
+- Revised handling of --write-auto option:
+  Revised handling of --write-auto option to avoid unwanted log messages.
+  Also slightly modified log messages for reasons of consistency.
+  Affects: dcmapps/include/dcmtk/dcmapps/dcm2img.h
+
+- Added check to make sure: HighBit < BitsAllocated:
+  Added check to the image preprocessing to make sure that the value of
+  HighBit is always less than the value of BitsAllocated. Before, this
+  missing check could lead to memory corruption if an invalid combination
+  of values was retrieved from a malformed DICOM dataset.
+  Thanks to Emmanuel Tacheau from the Cisco Talos team
+  <vulndiscovery@external.cisco.com> for the report, sample file (PoC)
+  and detailed analysis. See TALOS-2024-2121 and CVE-2024-52333.
+  Affects: dcmimgle/libsrc/diimage.cc
+
+- Avoided warning on unchecked option --write-auto.
+  Affects: dcmapps/include/dcmtk/dcmapps/dcm2img.h
+
+**** Changes from 2024.12.31 (eichelberg)
+
+- Fixed data corruption in iconv passthrough mode:
+  Fixed a data corruption that occured if a string longer than 1024 characters
+  was run through OFiconv() with source and character set being identical
+  and the pass-through mode being enabled (i.e. DCMTK compiled with the macro
+  DCMTK_ENABLE_ICONV_PASSTHROUGH). In this situation, the pointer to the next
+  unprocessed input character was not updated.
+  Thanks to DCMTK forum user cschreib for the bug report and test program.
+  This closes DCMTK issue #1143.
+  Affects: oficonv/libsrc/citrus_iconv_none.c
+
+**** Changes from 2024.12.29 (eichelberg)
+
+- Fixed thread issues in oficonv code:
+  Fixed various thread issues in the oficonv module reported by Valgrind's
+  DRD tool by moving some attributes that are modified during a call to
+  OFiconv_open() from the structure that is shared between multiple
+  iconv handles (struct _citrus_iconv_shared) to the structure containing
+  the unique attributes of each handle (struct _citrus_iconv).
+  Also added a read-write lock protecting accesses to the oficonv
+  logger callback.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the bug report
+  and test program demonstrating the issue.
+  This closes DCMTK issue #1137.
+  Affects: oficonv/libsrc/citrus_iconv_local.h
+           oficonv/libsrc/citrus_iconv_std.c
+           oficonv/libsrc/citrus_lock.h
+           oficonv/libsrc/oficonv_iconv.c
+           oficonv/libsrc/oficonv_logger.c
+
+**** Changes from 2024.12.28 (eichelberg)
+
+- Fixed frame size calculation for special cases:
+  DcmElement::getUncompressedFrameSize() now takes into account special cases
+  such as compressed images where Bits Allocated has a value that is not a
+  multiple of 8, but is overwritten during decompression anyway. In the case
+  of compressed images, the active decoder is now looked up and its behavior is
+  taken into account in the calculation.
+  This closes DCMTK issue #1140.
+  Added:   dcmdata/tests/tfrmsiz.cc
+  Affects: dcmdata/include/dcmtk/dcmdata/dccodec.h
+           dcmdata/include/dcmtk/dcmdata/dcelem.h
+           dcmdata/include/dcmtk/dcmdata/dcpixel.h
+           dcmdata/include/dcmtk/dcmdata/dcrleccd.h
+           dcmdata/include/dcmtk/dcmdata/dcrlecce.h
+           dcmdata/libsrc/dccodec.cc
+           dcmdata/libsrc/dcelem.cc
+           dcmdata/libsrc/dcpixel.cc
+           dcmdata/libsrc/dcrleccd.cc
+           dcmdata/libsrc/dcrlecce.cc
+           dcmdata/tests/CMakeLists.txt
+           dcmdata/tests/Makefile.in
+           dcmdata/tests/tests.cc
+           dcmjpeg/include/dcmtk/dcmjpeg/djcodecd.h
+           dcmjpeg/include/dcmtk/dcmjpeg/djcodece.h
+           dcmjpeg/libsrc/djcodecd.cc
+           dcmjpeg/libsrc/djcodece.cc
+           dcmjpls/include/dcmtk/dcmjpls/djcodecd.h
+           dcmjpls/include/dcmtk/dcmjpls/djcodece.h
+           dcmjpls/libsrc/djcodecd.cc
+           dcmjpls/libsrc/djcodece.cc
+
+**** Changes from 2024.12.27 (riesmeier)
+
+- Fixed source code formatting.
+  Affects: dcmimage/libsrc/dipitiff.cc
+
+**** Changes from 2024.12.24 (eichelberg)
+
+- Fixed TIFF export on Windows:
+  Fixed the TIFF export option of the dcm2img tool, which did not work
+  on 32-bit and 64 bit Windows builds.
+  Affects: dcmimage/libsrc/dipitiff.cc
+
+**** Changes from 2024.12.20 (eichelberg)
+
+- Added option that allows to relax GSPS validation:
+  Added an option to the validation code for Grayscale Softcopy Presentation
+  States that allows to relax the rule that all images referenced from one
+  presentation state must belong to the same SOP class. The rule can either
+  be relaxed to permit related "for presentation" and "for processing"
+  SOP classes, or this specific check can be completely disabled.
+  Thanks to Oliver Klerx <klerx@phoenix-pacs.de> for the proposal and patch.
+  Affects: dcmpstat/apps/dcmpschk.cc
+           dcmpstat/apps/dcmpsmk.cc
+           dcmpstat/apps/dcmpsrcv.cc
+           dcmpstat/docs/dcmpschk.man
+           dcmpstat/docs/dcmpsmk.man
+           dcmpstat/etc/dcmpstat.cfg
+           dcmpstat/include/dcmtk/dcmpstat/dvpscf.h
+           dcmpstat/include/dcmtk/dcmpstat/dvpsri.h
+           dcmpstat/libsrc/dvpscf.cc
+           dcmpstat/libsrc/dvpsri.cc
+
+**** Changes from 2024.12.18 (eichelberg)
+
+- Properly handle unknown "localhost" in DVPSIPCClient:
+  The request to resolve the hostname "localhost" to an IPv4 address
+  may fail under certain circumstances (e.g. in a IPv6 only environment).
+  This situation is now handled properly.
+  Thanks to Oliver Klerx <klerx@phoenix-pacs.de> for the bug report and patch.
+  Affects: dcmpstat/libsrc/dvpsmsg.cc
+
+- Simplified DcmQuantColorTable::computeHistogram():
+  Simplified code to avoid bogus error reports from Cppcheck.
+  Thanks to Oliver Klerx <klerx@phoenix-pacs.de> for the suggestion and patch.
+  Affects: dcmimage/libsrc/diqtctab.cc
+
+- Removed duplicate library dependencies (part 2):
+  Removed link libraries that are automatically included by CMake as
+  dependencies from other libraries. This avoids the code to be linked
+  against the same library multiple times, which causes warnings on MacOS.
+  Affects: dcmdata/apps/CMakeLists.txt
+           dcmdata/tests/CMakeLists.txt
+           dcmect/tests/CMakeLists.txt
+           dcmfg/tests/CMakeLists.txt
+           dcmjpls/apps/CMakeLists.txt
+           dcmnet/apps/CMakeLists.txt
+           dcmpstat/apps/CMakeLists.txt
+           dcmpstat/tests/CMakeLists.txt
+           dcmrt/apps/CMakeLists.txt
+           dcmrt/tests/CMakeLists.txt
+           dcmtls/tests/CMakeLists.txt
+           dcmwlm/apps/CMakeLists.txt
+           dcmwlm/tests/CMakeLists.txt
+
+**** Changes from 2024.12.17 (eichelberg)
+
+- Fixed padding of compressed JPEG-LS bitstream:
+  When using the cooked JPEG-LS encoder, odd-length bitstreams were padded with
+  a trailing zero byte (corresponding to the --padding-zero command line option)
+  instead of a an extended EOI marker.
+  Thanks to Mathieu Malaterre <mathieu.malaterre@gmail.com> for the bug report and pull request.
+  This closes Github pull request #111.
+  Affects: dcmjpls/libsrc/djcodece.cc
+
+- Removed duplicate library dependencies:
+  Removed link libraries that are automatically included by CMake as
+  dependencies from other libraries. This avoids the code to be linked
+  against the same library multiple times, which causes warnings on MacOS.
+  Affects: dcmapps/apps/CMakeLists.txt
+
+**** Changes from 2024.12.17 (fedorov)
+
+- Fix environ for Apple:
+  On Apple systems, define environ by using _NSGetEnviron() from
+  crt_externs.h.
+  Affects: ofstd/libsrc/ofstub.cc
+
+**** Changes from 2024.12.16 (riesmeier)
+
+- Replaced call of delete also in destructor.
+  Affects: dcmimgle/libsrc/dimoimg.cc
+
+- Replaced call of delete by delete[]:
+  Memory that was allocated with new[] should be deleted with delete[].
+  Thanks to Oliver Klerx <klerx@phoenix-pacs.de> for the report.
+  Affects: dcmimgle/libsrc/dimoimg.cc
+
+**** Changes from 2024.12.13 (eichelberg)
+
+- Updated version information for 3.6.9+ development.
+  Affects: config/configure
+           config/configure.in
+           config/confmod
+
+- Updated version information for 3.6.9+ development:
+  Updated version information marking the start of DCMTK development post minor
+  release 3.6.9.
+  Moved official ANNOUNCE file of the DCMTK release 3.6.9 to the "docs"
+  subfolder and replaced the main ANNOUNCE file with a "dummy".
+  Added:   docs/ANNOUNCE.369
+  Affects: ANNOUNCE
+           CMake/dcmtkPrepare.cmake
+           VERSION
+
+- Updated Github workflow config.
+  Affects: .github/workflows/cmake-win.yml
+
+**** Changes from 2024.12.11 (riesmeier)
+
+- Added missing package date.
+  Affects: config/configure
+           config/configure.in
+
+**** Changes from 2024.12.11 (eichelberg)
+
+- Updated PACKAGE version settings.
+  Affects: config/configure
+           config/configure.in
+
+- Updated configure files for upcoming release.
+  Affects: config/configure
+           config/configure.in
index a44c621546da8c25fa64c747ef64357a0dfd2742..372e93c247d608ea495508dcbc2f5f6ff5b10ce0 100644 (file)
@@ -1,4 +1,4 @@
-.TH "cda2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "cda2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 cda2dcm \- Encapsulate CDA file into DICOM file format
@@ -12,221 +12,10 @@ cda2dcm [options] cdafile-in dcmfile-out
 .PP
 .SH "DESCRIPTION"
 .PP
-The \fBcda2dcm\fP utility reads a CDA file (\fIcdafile-in\fP), converts it to a DICOM Encapsulated CDA Storage SOP instance and stores the converted data to an output file (\fIdcmfile-out\fP)\&.
-.SH "PARAMETERS"
+The \fBcda2dcm\fP tool is deprecated\&. Use \fBdcmencap\fP instead, which supports the same command line parameters, and more\&.
+.SH "SEE ALSO"
 .PP
-.PP
-.nf
-cdafile-in   CDA input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-.fi
-.PP
-.SH "OPTIONS"
-.PP
-.SS "general options"
-.PP
-.nf
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-.fi
-.PP
-.SS "DICOM document options"
-.PP
-.nf
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-
-override CDA file data:
-
-  -ov  --no-override
-         CDA patient and document data must match study,
-         series or manually entered information (default)
-
-  +ov  --override
-         data obtained from the CDA file will be overwritten
-         by study, series, or manually entered information
-.fi
-.PP
-.SS "processing options"
-.PP
-.nf
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-.fi
-.PP
-.SS "output options"
-.PP
-.nf
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-.fi
-.PP
-.SH "NOTES"
-.PP
-.SS "Attribute Sources"
-The application may be fed with some additional input for filling mandatory (and optional) attributes in the new DICOM file like patient, study and series information:
-.PP
-.IP "\(bu" 2
-The \fI--key\fP option can be used to add further attributes to the DICOM output file\&.
-.IP "\(bu" 2
-It is also possible to specify sequences, items and nested attributes using the \fI--key\fP option\&. In these cases, a special 'path' notation has to be used\&. Details on this path notation can be found in the documentation of \fBdcmodify\fP\&.
-.IP "\(bu" 2
-The \fI--key\fP option can be present more than once\&.
-.IP "\(bu" 2
-The value part (after the '=') may be absent causing the attribute to be set with zero length\&.
-.IP "\(bu" 2
-Please be advised that the \fI--key\fP option is applied at the very end, just before saving the DICOM file, so there is no value checking whatsoever\&.
-.PP
-.SH "LOGGING"
-.PP
-The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
-.PP
-In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
-.SH "COMMAND LINE"
-.PP
-All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
-.PP
-Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
-.PP
-In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
-.SH "EXIT CODES"
-.PP
-The \fBcda2dcm\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
-.SS "general"
-.PP
-.nf
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-.fi
-.PP
-.SS "input file errors"
-.PP
-.nf
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-.fi
-.PP
-.SS "output file errors"
-.PP
-.nf
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-.fi
-.PP
-.SH "ENVIRONMENT"
-.PP
-The \fBcda2dcm\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
-.PP
-The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+\fBdcmencap\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2018-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2018-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 8d62b90440877f99b38903aa16010484d2c9990e..12d6e0c1a055aab132b843aa61d5e9fe62d80829 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2cda" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2cda" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2cda \- Extract CDA file from DICOM encapsulated CDA
@@ -12,163 +12,10 @@ dcm2cda [options] dcmfile-in cdafile-out
 .PP
 .SH "DESCRIPTION"
 .PP
-The \fBdcm2cda\fP utility reads a DICOM file of the Encapsulated CDA Storage SOP Class (\fIdcmfile-in\fP), extracts the embedded CDA document and writes it to an output file (\fIcdafile-out\fP)\&. Optionally a command can be executed after the creation of the CDA file\&.
-.SH "PARAMETERS"
-.PP
-.PP
-.nf
-dcmfile-in   DICOM input filename ("-" for stdin)
-
-cdafile-out  CDA output filename
-.fi
-.PP
-.SH "OPTIONS"
-.PP
-.SS "general options"
-.PP
-.nf
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-.fi
-.PP
-.SS "input options"
-.PP
-.nf
-input file format:
-
-  +f   --read-file
-         read file format or data set (default)
-
-  +fo  --read-file-only
-         read file format only
-
-  -f   --read-dataset
-         read data set without file meta information
-
-input transfer syntax:
-
-  -t=  --read-xfer-auto
-         use TS recognition (default)
-
-  -td  --read-xfer-detect
-         ignore TS specified in the file meta header
-
-  -te  --read-xfer-little
-         read with explicit VR little endian TS
-
-  -tb  --read-xfer-big
-         read with explicit VR big endian TS
-
-  -ti  --read-xfer-implicit
-         read with implicit VR little endian TS
-
-parsing of odd-length attributes:
-
-  +ao  --accept-odd-length
-         accept odd length attributes (default)
-
-  +ae  --assume-even-length
-         assume real length is one byte larger
-
-handling of undefined length UN elements:
-
-  +ui  --enable-cp246
-         read undefined len UN as implicit VR (default)
-
-  -ui  --disable-cp246
-         read undefined len UN as explicit VR
-
-handling of defined length UN elements:
-
-  -uc  --retain-un
-         retain elements as UN (default)
-
-  +uc  --convert-un
-         convert to real VR if known
-
-automatic data correction:
-
-  +dc  --enable-correction
-         enable automatic data correction (default)
-
-  -dc  --disable-correction
-         disable automatic data correction
-
-bitstream format of deflated input:
-
-  +bd  --bitstream-deflated
-         expect deflated bitstream (default)
-
-  +bz  --bitstream-zlib
-         expect deflated zlib bitstream
-.fi
-.PP
-.SH "LOGGING"
-.PP
-The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
-.PP
-In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
-.SH "EXIT CODES"
-.PP
-The \fBdcm2cda\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
-.SS "general"
-.PP
-.nf
-EXITCODE_NO_ERROR                         0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
-.fi
-.PP
-.SS "input file errors"
-.PP
-.nf
-EXITCODE_CANNOT_READ_INPUT_FILE          20
-EXITCODE_NO_INPUT_FILES                  21
-EXITCODE_INVALID_INPUT_FILE              22
-.fi
-.PP
-.SS "output file errors"
-.PP
-.nf
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
-.fi
-.PP
-.SH "COMMAND LINE"
-.PP
-All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
-.PP
-Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
-.PP
-In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
-.SH "ENVIRONMENT"
-.PP
-The \fBdcm2cda\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
-.PP
-The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+The \fBdcm2cda\fP tool is deprecated\&. Use \fBdcmdecap\fP instead, which supports the same command line parameters, and more\&.
 .SH "SEE ALSO"
 .PP
-\fBcda2dcm\fP(1)
+\fBdcmdecap\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2023-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2023-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index e745b4f1d2b05dd1e087e3573f5435788c3483b9..2b18b2f0fabbb883947d50fc024f0516dab62fc8 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2img" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2img" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2img \- Convert DICOM image to standard image format
@@ -171,6 +171,22 @@ color space conversion (JPEG compressed images only):
   +cn   --conv-never
           never convert color space
 
+bits stored:
+
+  +bs  --bits-stored-fix
+         correct inconsistent bits stored value (default)
+
+  # If the value of BitsStored in the compressed bitstream is smaller
+  # than the value in the DICOM dataset, update the value in the dataset
+  # (JPEG compressed images only)
+
+  -bs  --bits-stored-keep
+         preserve inconsistent bits stored value
+
+  # Keep the value of BitsStored even if inconsistent with the
+  # compressed bitstream. This may help in correctly decoding some
+  # defective images JPEG compressed images only)
+
 workaround options for incorrect encodings (JPEG compressed images only):
 
   +w6   --workaround-pred6
@@ -555,4 +571,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBimg2dcm\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 46d7457e5191d811491c5d99e4e0394ace0a4beb..3ad9e0dafc7105d2b46f37d888cba3ec93b8c701 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2json" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2json" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2json \- Convert DICOM file and data set to JSON
@@ -108,6 +108,27 @@ encoding of IS and DS (integer/decimal string) elements:
 
   -is  --is-ds-string
          always encode as string
+
+bulk data URI options:
+
+  -b   --bulk-disabled
+         write everything as inline binary (default)
+
+  +b   --bulk-enabled
+         write large attributes as bulk data
+
+  +bz  --bulk-size  [s]ize: integer (default: 1)
+         use bulk data for attributes >= s kBytes
+
+  +bp  --bulk-uri-prefix  [u]ri prefix: string
+         use prefix u when generating bulk data URIs (default: file URI)
+
+  +bd  --bulk-dir  [d]irectory: string
+         write bulk data files to d (default: '.')
+
+  +bs  --bulk-subdir
+         create subdirectory for each SOP instance
+         (default: no subdirectory)
 .fi
 .PP
 .SS "output options"
@@ -291,13 +312,37 @@ The basic structure of the JSON output created from a DICOM file looks like the
 .fi
 .PP
 .SS "Bulk Data"
-Binary data, i\&.e\&. DICOM element values with Value Representations (VR) of OB or OW, as well as OD, OF, OL, OV and UN values are always written as 'InlineBinary' (base64 encoding) to the JSON output\&. A future version of this tool might optionally use a 'BulkDataURI' instead, i\&.e\&. the WADO-RS URL of a bulk data item that contains the element value\&. This would be particularly useful for large amounts of data, such as pixel data\&.
+By default, binary data, i\&.e\&. DICOM element values with Value Representations (VR) of OB, OD, OF, OL, OV, OW, and UN values are written as 'InlineBinary' (base64 encoding) to the JSON output\&. Option \fI--bulk-enabled\fP causes binary data as well as DS, FD, FL, IS, SV and UV to be replaced by 'BulkDataURI' values if the element value is larger than the cut-off threshold (default: 1 kByte)\&. The cut-off threshold can be specified with the \fI--bulk-size\fP option\&. The element values themselves are written as files to the directory given by the \fI--bulk-dir\fP option (default: current directory)\&. The filename is based on a SHA-256 checksum of the element value\&. By default, file URIs are generated that point to the bulk directory\&. For production use, a URI prefix for a WADO-RS service over which the element values can be retrieved should be specified using the \fI--bulk-uri-prefix\fP option\&. This can be implemented by configuring a web server that has read access to \fBdcm2json's\fP bulk directory\&. Finally, the option \fI--bulk-subdir\fP will cause a separate subdirectory to be created (and used in the bulk data URI) for each distinct SOP instance\&.
+.PP
+Note that the JSON syntax for the representation of encapsulated pixel data in 'InlineBinary' form is unspecified in DICOM, as is the JSON representation of encapsulated multi-frame pixel data\&. These DICOM files cannot be converted to JSON using \fBdcm2json\fP\&.
+.PP
+The file name extension for the bulk data files generated can be used to determine the MIME type that should be returned by the WADO-RS server:
+.PP
+.PP
+.nf
+  Extension     MIME Type
+
+  .bin          application/octet-stream
+  .jpeg         image/jpeg
+  .dicom-rle    image/dicom-rle
+  .jls          image/jls
+  .jp2          image/jp2
+  .jpx          image/jpx
+  .jphc         image/jphc
+  .jxl          image/jxl
+  .mpeg         video/mpeg
+  .mp4          video/mp4
+  .H265         video/H265
+.fi
+.PP
+.PP
+Finally, it should be noted that bulk data will be written 'as is', i\&.e\&. \fBdcm2json\fP will not attempt to validate or modify the element value in any way\&. For example, \fBdcm2json\fP will not add a JFIF header in the case of JPEG baseline compressed images, which some JPEG viewers may expect\&.
 .SH "NOTES"
 .PP
 .SS "Numbers as Strings"
 The DICOM standard allows certain numeric DICOM value representations, DS, IS, SV and UV, to be converted either to a JSON number or a JSON string\&. \fBdcm2json\fP converts DS and IS values to JSON numbers if they are valid decimal strings or integer strings, and to strings if they contain any illegal character\&. \fBdcm2json\fP converts SV and UV values to numbers if they are not larger than 9007199254740991ll or smaller than -9007199254740991ll, and to strings otherwise\&. While the JSON specification permits larger numbers, these are the largest integers that JavaScript can handle\&. Therefore, many JSON parsers cannot process larger numbers\&.
 .SS "Character Encoding"
-As required by the DICOM JSON encoding, \fBdcm2json\fP always creates output in Unicode UTF-8 encoding and converts DICOM datasets accordingly\&. If this is not possible, for example because DCMTK has been compiled without character set conversion support, an error is returned\&.
+As required by the DICOM JSON encoding, \fBdcm2json\fP always creates output in Unicode UTF-8 encoding and converts DICOM data sets accordingly\&. If this is not possible, for example because DCMTK has been compiled without character set conversion support, an error is returned\&.
 .SH "LOGGING"
 .PP
 The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
@@ -351,4 +396,4 @@ The \fBdcm2json\fP utility will attempt to load character set mapping tables\&.
 The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICONVPATH\fP environment variable can be used to specify a different location\&. If a different location is specified, those mapping tables also replace any built-in tables\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2016-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2016-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 3385aa45c013a4bb25848e19a396eb3bf8d68673..73b3529efda8eacc554aa5c68f30f9315950827f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2pdf" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2pdf" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2pdf \- Extract PDF file from DICOM encapsulated PDF
@@ -12,182 +12,10 @@ dcm2pdf [options] dcmfile-in pdffile-out
 .PP
 .SH "DESCRIPTION"
 .PP
-The \fBdcm2pdf\fP utility reads a DICOM file of the Encapsulated PDF Storage SOP Class (\fIdcmfile-in\fP), extracts the embedded PDF document and writes it to an output file (\fIpdffile-out\fP)\&. Optionally a command can be executed after the creation of the PDF file\&.
-.SH "PARAMETERS"
-.PP
-.PP
-.nf
-dcmfile-in   DICOM input filename ("-" for stdin)
-
-pdffile-out  PDF output filename
-.fi
-.PP
-.SH "OPTIONS"
-.PP
-.SS "general options"
-.PP
-.nf
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-.fi
-.PP
-.SS "input options"
-.PP
-.nf
-input file format:
-
-  +f   --read-file
-         read file format or data set (default)
-
-  +fo  --read-file-only
-         read file format only
-
-  -f   --read-dataset
-         read data set without file meta information
-
-input transfer syntax:
-
-  -t=  --read-xfer-auto
-         use TS recognition (default)
-
-  -td  --read-xfer-detect
-         ignore TS specified in the file meta header
-
-  -te  --read-xfer-little
-         read with explicit VR little endian TS
-
-  -tb  --read-xfer-big
-         read with explicit VR big endian TS
-
-  -ti  --read-xfer-implicit
-         read with implicit VR little endian TS
-
-parsing of odd-length attributes:
-
-  +ao  --accept-odd-length
-         accept odd length attributes (default)
-
-  +ae  --assume-even-length
-         assume real length is one byte larger
-
-handling of undefined length UN elements:
-
-  +ui  --enable-cp246
-         read undefined len UN as implicit VR (default)
-
-  -ui  --disable-cp246
-         read undefined len UN as explicit VR
-
-handling of defined length UN elements:
-
-  -uc  --retain-un
-         retain elements as UN (default)
-
-  +uc  --convert-un
-         convert to real VR if known
-
-automatic data correction:
-
-  +dc  --enable-correction
-         enable automatic data correction (default)
-
-  -dc  --disable-correction
-         disable automatic data correction
-
-bitstream format of deflated input:
-
-  +bd  --bitstream-deflated
-         expect deflated bitstream (default)
-
-  +bz  --bitstream-zlib
-         expect deflated zlib bitstream
-.fi
-.PP
-.SS "processing options"
-execution options:
-.PP
-.nf
-  -x   --exec  [c]ommand: string
-         execute command c after PDF extraction
-
-.fi
-.PP
-.SH "NOTES"
-.PP
-Option \fI--exec\fP allows for the execution of a certain command line after the creation of the PDF document\&. The command line to be executed is passed to this option as a parameter\&. The specified command line may contain the placeholder '#f', which will be replaced by the PDF filename at run time\&. The specified command line is executed in the foreground, i\&.e\&. \fBpdf2dcm\fP will be blocked until the command terminates\&.
-.SH "LOGGING"
-.PP
-The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
-.PP
-In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
-.SH "EXIT CODES"
-.PP
-The \fBdcm2pdf\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
-.SS "general"
-.PP
-.nf
-EXITCODE_NO_ERROR                         0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
-.fi
-.PP
-.SS "input file errors"
-.PP
-.nf
-EXITCODE_CANNOT_READ_INPUT_FILE          20
-EXITCODE_NO_INPUT_FILES                  21
-EXITCODE_INVALID_INPUT_FILE              22
-.fi
-.PP
-.SS "output file errors"
-.PP
-.nf
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
-.fi
-.PP
-.SS "processing errors"
-.PP
-.nf
-EXITCODE_CANNOT_CONVERT_TO_UNICODE       80
-EXITCODE_CANNOT_WRITE_VALID_JSON         81
-.fi
-.PP
-.SH "COMMAND LINE"
-.PP
-All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
-.PP
-Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
-.PP
-In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
-.SH "ENVIRONMENT"
-.PP
-The \fBdcm2pdf\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
-.PP
-The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+The \fBdcm2pdf\fP tool is deprecated\&. Use \fBdcmdecap\fP instead, which supports the same command line parameters, and more\&.
 .SH "SEE ALSO"
 .PP
-\fBpdf2dcm\fP(1)
+\fBdcmdecap\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2007-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2007-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 47c9a4f90f8b3d58d4a2e201a9a5141713f9dbc2..fd13c56a9777323fa7bfd98a51f6ec1f085d6569 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2pnm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2pnm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2pnm \- Convert DICOM images to PGM/PPM, PNG, TIFF or BMP
@@ -18,4 +18,4 @@ The \fBdcm2pnm\fP tool is deprecated\&. Use \fBdcm2img\fP instead, which support
 \fBdcm2img\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index df70708355344fb17ed1093b113ce94272fe82b7..220814f5d103296fd9e228863c927f958a2f012a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcm2xml" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcm2xml" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcm2xml \- Convert DICOM file and data set to XML
@@ -293,4 +293,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBxml2dcm\fP(1), \fBdcmconv\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2002-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2002-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 3fefcd19ae9a17071db6a5e4c142f2d3e1e70afd..d73b9bd831b56325d5d2bf70a0a888c997298673 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmcjpeg" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmcjpeg" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmcjpeg \- Encode DICOM file to JPEG transfer syntax
@@ -647,4 +647,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmdjpeg\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 88a08f2b13ea7d7d2005e0e4b1231e13d8080440..2c66fb4fcb33a706396fd1fb833cda177a7e1afa 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmcjpls" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmcjpls" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmcjpls \- Encode DICOM file to JPEG-LS transfer syntax
@@ -339,4 +339,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmdjpls\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2009-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2009-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 26b80c6802da755bb8d42ff9ab70bbb5a41d1a02..934e30f4e08df035ed61c8402e26e9c10ca55659 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmconv" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmconv" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmconv \- Convert DICOM file encoding
@@ -351,4 +351,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBdcmdump\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1994-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1994-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index fc4f39815314e5a4dde4cda58a9c64fb768b85d6..f392ae00c8308eb2b464ae4468dc7e606830ec11 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmcrle" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmcrle" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmcrle \- Encode DICOM file to RLE transfer syntax
@@ -212,4 +212,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmdrle\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2002-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2002-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
diff --git a/doxygen/manpages/man1/dcmdecap.1 b/doxygen/manpages/man1/dcmdecap.1
new file mode 100644 (file)
index 0000000..e7f1cb4
--- /dev/null
@@ -0,0 +1,192 @@
+.TH "dcmdecap" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
+.nh
+.SH NAME
+dcmdecap \- Extract encapsulated file from DICOM encapsulated storage object
+
+.SH "SYNOPSIS"
+.PP
+.PP
+.nf
+dcmdecap [options] dcmfile-in encfile-out
+.fi
+.PP
+.SH "DESCRIPTION"
+.PP
+The \fBdcmdecap\fP utility reads a DICOM file of one of the Encapsulated Storage SOP Classes (\fIdcmfile-in\fP), extracts the embedded document and writes it to an output file (\fIencfile-out\fP)\&. Optionally a command can be executed after the creation of the output file\&.
+.SH "PARAMETERS"
+.PP
+.PP
+.nf
+dcmfile-in   DICOM input filename ("-" for stdin)
+
+encfile-out  Encapsulated document output filename ("-" for stdout)
+.fi
+.PP
+.SH "OPTIONS"
+.PP
+.SS "general options"
+.PP
+.nf
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+.fi
+.PP
+.SS "input options"
+.PP
+.nf
+input file format:
+
+  +f   --read-file
+         read file format or data set (default)
+
+  +fo  --read-file-only
+         read file format only
+
+  -f   --read-dataset
+         read data set without file meta information
+
+input transfer syntax:
+
+  -t=  --read-xfer-auto
+         use TS recognition (default)
+
+  -td  --read-xfer-detect
+         ignore TS specified in the file meta header
+
+  -te  --read-xfer-little
+         read with explicit VR little endian TS
+
+  -tb  --read-xfer-big
+         read with explicit VR big endian TS
+
+  -ti  --read-xfer-implicit
+         read with implicit VR little endian TS
+
+parsing of odd-length attributes:
+
+  +ao  --accept-odd-length
+         accept odd length attributes (default)
+
+  +ae  --assume-even-length
+         assume real length is one byte larger
+
+handling of undefined length UN elements:
+
+  +ui  --enable-cp246
+         read undefined len UN as implicit VR (default)
+
+  -ui  --disable-cp246
+         read undefined len UN as explicit VR
+
+handling of defined length UN elements:
+
+  -uc  --retain-un
+         retain elements as UN (default)
+
+  +uc  --convert-un
+         convert to real VR if known
+
+automatic data correction:
+
+  +dc  --enable-correction
+         enable automatic data correction (default)
+
+  -dc  --disable-correction
+         disable automatic data correction
+
+bitstream format of deflated input:
+
+  +bd  --bitstream-deflated
+         expect deflated bitstream (default)
+
+  +bz  --bitstream-zlib
+         expect deflated zlib bitstream
+.fi
+.PP
+.SS "processing options"
+execution options:
+.PP
+.nf
+  -x   --exec  [c]ommand: string
+         execute command c after document extraction
+
+.fi
+.PP
+.SH "NOTES"
+.PP
+Option \fI--exec\fP allows for the execution of a certain command line after the creation of the PDF document\&. The command line to be executed is passed to this option as a parameter\&. The specified command line may contain the placeholder '#f', which will be replaced by the output filename at run time\&. The specified command line is executed in the foreground, i\&.e\&. \fBdcmdecap\fP will be blocked until the command terminates\&.
+.SH "LOGGING"
+.PP
+The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
+.PP
+In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
+.SH "EXIT CODES"
+.PP
+The \fBdcmdecap\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
+.SS "general"
+.PP
+.nf
+EXITCODE_NO_ERROR                         0
+EXITCODE_COMMANDLINE_SYNTAX_ERROR         1
+.fi
+.PP
+.SS "input file errors"
+.PP
+.nf
+EXITCODE_CANNOT_READ_INPUT_FILE          20
+EXITCODE_NO_INPUT_FILES                  21
+EXITCODE_INVALID_INPUT_FILE              22
+.fi
+.PP
+.SS "output file errors"
+.PP
+.nf
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE        40
+.fi
+.PP
+.SS "processing errors"
+.PP
+.nf
+EXITCODE_EXEC_FAILED                     91
+.fi
+.PP
+.SH "COMMAND LINE"
+.PP
+All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
+.PP
+Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
+.PP
+In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
+.SH "ENVIRONMENT"
+.PP
+The \fBdcmdecap\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
+.PP
+The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+.SH "SEE ALSO"
+.PP
+\fBdcmencap\fP(1)
+.SH "COPYRIGHT"
+.PP
+Copyright (C) 2007-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index cedf8f2073f65a6f16f5274b299907b403a754d1..f26636e09a5396e13cc9b984ef93a94c2687981d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmdjpeg" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmdjpeg" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmdjpeg \- Decode JPEG-compressed DICOM file
@@ -144,6 +144,21 @@ planar configuration:
   # If the compressed image is a color image, store in color-by-plane
   # planar configuration.
 
+bits stored:
+
+  +bs  --bits-stored-fix
+         correct inconsistent bits stored value (default)
+
+  # If the value of BitsStored in the compressed bitstream is smaller
+  # than the value in the DICOM dataset, update the value in the dataset.
+
+  -bs  --bits-stored-keep
+         preserve inconsistent bits stored value
+
+  # Keep the value of BitsStored even if inconsistent with the
+  # compressed bitstream. This may help in correctly decoding some
+  # defective images.
+
 SOP Instance UID:
 
   +ud   --uid-default
@@ -302,4 +317,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmcjpeg\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 42faf5743199ee906e0b89a49bbbd8e980b9a818..99d80132d6aca00c6ce46969662d33740b8a5a2e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmdjpls" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmdjpls" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmdjpls \- Decode JPEG-LS compressed DICOM file
@@ -240,4 +240,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmcjpls\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2009-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2009-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index baf40c1ed8aafb99f9dd9be391187dea62555e06..738c41e213ff675f51ee912c386b9fa545e053fe 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmdrle" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmdrle" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmdrle \- Decode RLE-compressed DICOM file
@@ -206,4 +206,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmcrle\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2002-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany
+Copyright (C) 2002-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany
index 979780e46f42a21ae12a56449d104de4c291239b..fab122f3c2530252d4358592a17d4572ebc80972 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmdspfn" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmdspfn" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmdspfn \- Export standard display curves to a text file
@@ -143,4 +143,4 @@ In addition, one or more command files can be specified using an '@' sign as a p
 \fBdconvlum\fP(1), \fBdcod2lum\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1999-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1999-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 7e75a0b2849e186a501352d4f3b43a34e33cd976..51530409adb08c6d63f1d41d3ac16acf36adc320 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmdump" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmdump" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmdump \- Dump DICOM file and data set
@@ -364,4 +364,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBdump2dcm\fP(1), \fBdcmconv\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1994-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1994-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
diff --git a/doxygen/manpages/man1/dcmencap.1 b/doxygen/manpages/man1/dcmencap.1
new file mode 100644 (file)
index 0000000..f157caa
--- /dev/null
@@ -0,0 +1,271 @@
+.TH "dcmencap" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
+.nh
+.SH NAME
+dcmencap \- Encapsulate document into DICOM format
+
+.SH "SYNOPSIS"
+.PP
+.PP
+.nf
+dcmencap [options] docfile-in dcmfile-out
+.fi
+.PP
+.SH "DESCRIPTION"
+.PP
+The \fBdcmencap\fP utility reads a document file in one of the supported file formats, converts it to a SOP instance of the corresponding DICOM Encapsulated Storage SOP Class and stores the converted data in an output file (\fIdcmfile-out\fP)\&.
+.SH "PARAMETERS"
+.PP
+.PP
+.nf
+docfile-in   input filename to be converted
+
+dcmfile-out  DICOM output filename ("-" for stdout)
+.fi
+.PP
+.SH "OPTIONS"
+.PP
+.SS "general options"
+.PP
+.nf
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+.fi
+.PP
+.SS "input options"
+.PP
+.nf
+input file format:
+
+  +fa  --filetype-auto
+         automatically determine file type (default)
+
+  +fp  --filetype-pdf
+         expect PDF file
+
+  +fc  --filetype-cda
+         expect CDA file
+
+  +fs  --filetype-stl
+         expect STL file
+
+  +fm  --filetype-mtl
+         expect MTL file
+
+  +fo  --filetype-obj
+         expect OBJ file
+.fi
+.PP
+.SS "DICOM document options"
+.PP
+.nf
+document title:
+
+  +t   --title  [t]itle: string (default: empty)
+         document title
+
+  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
+         coded representation of document title defined by coding
+         scheme designator CSD, code value CV and code meaning CM
+
+patient data:
+
+  +pn  --patient-name  [n]ame: string
+         patient's name in DICOM PN syntax
+
+  +pi  --patient-id  [i]d: string
+         patient identifier
+
+  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
+         patient's birth date
+
+  +ps  --patient-sex  [s]ex: string (M, F or O)
+         patient's sex
+
+device data:
+
+  +mn  --manufacturer  [n]ame: string
+         manufacturer's name
+
+  +mm  --manufacturer-model  [n]ame: string
+         manufacturer's model name
+
+  +ds  --device-serial  [n]umber: string
+         device serial number
+
+  +sv  --software-versions  [v]ersions: string
+         software versions
+
+manufacturing 3d model data (STL/MTL/OBJ only):
+
+  +mu  --measurement-units  [CSD] [CV] [CM]: string
+         measurement units with coding scheme designator CSD,
+         code value CV and code meaning CM (default: UCUM, um, um)
+
+study and series:
+
+  +sg  --generate
+         generate new study and series UIDs (default)
+
+  +st  --study-from  [f]ilename: string
+         read patient/study data from DICOM file
+
+  +se  --series-from  [f]ilename: string
+         read patient/study/series data from DICOM file
+
+instance number:
+
+  +i1  --instance-one
+         use instance number 1 (default, not with +se)
+
+  +ii  --instance-inc
+         increment instance number (only with +se)
+
+  +is  --instance-set [i]nstance number: integer
+         use instance number i
+
+burned-in annotation:
+
+  +an  --annotation-yes
+         document contains patient identifying data (default)
+
+  -an  --annotation-no
+         document does not contain patient identifying data
+.fi
+.PP
+.SS "processing options"
+.PP
+.nf
+CDA processing options:
+
+  -ov  --no-override
+         CDA patient and document data must match study,
+         series or manually entered information (default)
+
+  +ov  --override
+         CDA's data will be overwritten by study, series
+         or manually entered information
+
+other processing options:
+
+  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
+         add further attribute
+.fi
+.PP
+.SS "output options"
+.PP
+.nf
+output transfer syntax:
+  +te  --write-xfer-little
+         write with explicit VR little endian (default)
+
+  +tb  --write-xfer-big
+         write with explicit VR big endian TS
+
+  +ti  --write-xfer-implicit
+         write with implicit VR little endian TS
+
+group length encoding:
+
+  -g   --group-length-remove
+         write without group length elements (default)
+
+  +g   --group-length-create
+         write with group length elements
+
+length encoding in sequences and items:
+
+  +e   --length-explicit
+         write with explicit lengths (default)
+
+  -e   --length-undefined
+         write with undefined lengths
+
+data set trailing padding (not with --write-dataset):
+
+  -p   --padding-off
+         no padding (implicit if --write-dataset)
+
+  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
+         align file on multiple of f bytes
+         and items on multiple of i bytes
+.fi
+.PP
+.SH "NOTES"
+.PP
+.SS "Attribute Sources"
+The application may be fed with some additional input for filling mandatory (and optional) attributes in the new DICOM file like patient, study and series information:
+.PP
+.IP "\(bu" 2
+The \fI--key\fP option can be used to add further attributes to the DICOM output file\&.
+.IP "\(bu" 2
+It is also possible to specify sequences, items and nested attributes using the \fI--key\fP option\&. In these cases, a special 'path' notation has to be used\&. Details on this path notation can be found in the documentation of \fBdcmodify\fP\&.
+.IP "\(bu" 2
+The \fI--key\fP option can be present more than once\&.
+.IP "\(bu" 2
+The value part (after the '=') may be absent causing the attribute to be set with zero length\&.
+.IP "\(bu" 2
+Please be advised that the \fI--key\fP option is applied at the very end, just before saving the DICOM file, so there is no value checking whatsoever\&.
+.PP
+.SH "LOGGING"
+.PP
+The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
+.PP
+In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
+.SH "COMMAND LINE"
+.PP
+All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
+.PP
+Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
+.PP
+In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
+.SH "EXIT CODES"
+.PP
+The \fBdcmencap\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
+.SS "general"
+.PP
+.nf
+EXITCODE_NO_ERROR                 0
+.fi
+.PP
+.SS "input file errors"
+.PP
+.nf
+EXITCODE_INVALID_INPUT_FILE       22
+.fi
+.PP
+.SS "output file errors"
+.PP
+.nf
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
+.fi
+.PP
+.SH "ENVIRONMENT"
+.PP
+The \fBdcmencap\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
+.PP
+The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+.SH "COPYRIGHT"
+.PP
+Copyright (C) 2018-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index a7ff3aea87096424ebae810835d4ecba49fbfeee..5d5f393240b6a72d4b91d742f51e07949599a39c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmftest" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmftest" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmftest \- Test if file uses DICOM part 10 format
@@ -28,4 +28,4 @@ All files specified on the command line are checked for the presence of the DICO
 \fBdcmgpdir\fP(1), \fBdcmmkdir\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1997-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1997-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 47c328fb41967648aaf73d80bfb7b6ad78e38f84..a2770dc4ec43ee6a6f7f3d279022d7c308eb5d8d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmgpdir" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmgpdir" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmgpdir \- Create a general purpose DICOMDIR
@@ -18,4 +18,4 @@ The \fBdcmgpdir\fP tool is deprecated\&. Use \fBdcmmkdir\fP instead, which suppo
 \fBdcmmkdir\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1996-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1996-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 6e92333a146e58f8c3d187b48a4379809f42302c..f036989dd14fc0151eb6798c491e8a098a3b7592 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmicmp" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmicmp" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmicmp \- Compare DICOM images and compute difference metrics
@@ -300,4 +300,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcm2pnm\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2018-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2018-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 8acd3984614839c70650c1d1f8ef30ce9e69911c..ff18cfe1121f733afa946755a7a5f9c6c1b0005e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmj2pnm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmj2pnm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmj2pnm \- Convert DICOM images to PGM/PPM, PNG, TIFF, JPEG or BMP
@@ -18,4 +18,4 @@ The \fBdcmj2pnm\fP tool is deprecated\&. Use \fBdcm2img\fP instead, which suppor
 \fBdcm2img\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 68f1beabf6a9df8bc7b2074bbdaec42937948664..564c5bb413e00c92903471564c95e32ddba24136 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcml2pnm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcml2pnm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcml2pnm \- Convert DICOM images to PGM/PPM, PNG, TIFF or BMP
@@ -18,4 +18,4 @@ The \fBdcml2pnm\fP tool is deprecated\&. Use \fBdcm2img\fP instead, which suppor
 \fBdcm2img\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 2b9ce5f3b40e2e21f46c5031905e62df7944cb42..66829581bfdbb033d4826d9c0a1594e09a45b007 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmmkcrv" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmmkcrv" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmmkcrv \- Add 2D curve data to image
@@ -125,4 +125,4 @@ The \fBdcmmkcrv\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 51b7732609e35209a9add7702c6250327fdf702e..02ddab24ae3034b9791801598cf373eda8eb2efb 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmmkdir" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmmkdir" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmmkdir \- Create a DICOMDIR file
@@ -429,4 +429,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmgpdir\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index a8880ea1a738663131e902e350431d54f7950bb9..291bbe967d57b5605619a8868dafff039396680d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmmklut" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmmklut" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmmklut \- Create DICOM look-up tables
@@ -189,4 +189,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fI<datadir>/philips\&.lut\fP - sample LUT in text format
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index f884b39974a0d3892c7ffc78938070933fe870f7..2281cc978ac37434671f52ac51f04a26db8027fd 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmodify" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmodify" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmodify \- Modify DICOM files
@@ -442,4 +442,4 @@ The \fBdcmodify\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2003-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2003-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index af059f71b057d2e7938d00297cebb6d700aca677..f53e5f37f02087766dfa981b47332585c2964524 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmp2pgm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmp2pgm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmp2pgm \- Read DICOM image and presentation state and render bitmap
@@ -111,4 +111,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fI<etcdir>/dcmpstat\&.cfg\fP - sample configuration file
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 9ede33c5482d7ed952fc3e58475ad474eb608513..6a49adfbb27972cd0917b19b437a76069bbaab39 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmprscp" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmprscp" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmprscp \- DICOM basic grayscale print management SCP
@@ -90,4 +90,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmprscu\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1999-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1999-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 0b514a6bdf8ab3e44c7ac30e040c6439fe9505db..ee41ce4117b2a9f8bfa5c2ce882ce6a11d8843e5 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmprscu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmprscu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmprscu \- Print spooler for presentation state viewer
@@ -147,4 +147,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmprscp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1999-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1999-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 3e5f7d5dc992d2ac61eafd0a38f88070e022796f..94c915a45aa49b3ac945d3cee08405759acdb622 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmpschk" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmpschk" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmpschk \- Checking tool for presentation states
@@ -59,6 +59,21 @@ dcmfile-in  presentation state file(s) to be checked
          use config file f for the logger
 .fi
 .PP
+.SS "validation options"
+.PP
+.nf
+       --validate-std
+         images referenced by GSPS must belong to the
+         same SOP class (default)
+
+       --validate-related
+         images referenced by GSPS may belong to related
+         'for presentation' and 'for processing' SOP class
+
+       --validate-relaxed
+         images referenced by GSPS may be any SOP class
+.fi
+.PP
 .SH "LOGGING"
 .PP
 The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
@@ -78,4 +93,4 @@ The \fBdcmpschk\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2000-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2000-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 2988b13ef5740510fdfea03d17bf0d08cfd261dc..3b0aa5785a379c6ebf246c6a00088a5c6486f4b7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmpsmk" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmpsmk" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmpsmk \- Create DICOM grayscale softcopy presentation state
@@ -157,6 +157,21 @@ location of referenced image:
          image located on storage medium
 .fi
 .PP
+.SS "validation options"
+.PP
+.nf
+       --validate-std
+          images referenced by GSPS must belong to the
+          same SOP class (default)
+
+       --validate-related
+          images referenced by GSPS may belong to related
+          'for presentation' and 'for processing' SOP class
+
+       --validate-relaxed
+          images referenced by GSPS may be any SOP class
+.fi
+.PP
 .SS "output options"
 .PP
 .nf
@@ -197,4 +212,4 @@ The \fBdcmpsmk\fP utility will attempt to load DICOM data dictionaries specified
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 65712dec0ed061613696825b2df5424c81123fc9..fe4364aa48c11ebac5dacf969fba321e8b78a53a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmpsprt" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmpsprt" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmpsprt \- Read DICOM images and presentation states and render print job
@@ -274,4 +274,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmprscu\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1999-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1999-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index f6d84fa06893f9e4f8f3eb5b1ffbd77b98ab6b05..db9c798eb2acebd440d3b2967b1fb9540eeb6d3c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmpsrcv" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmpsrcv" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmpsrcv \- Network receive for presentation state viewer
@@ -79,4 +79,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmpssnd\fP(1), \fBstorescp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 162b5a7760d0dc8c7a7086d37a267f9f3ada37c7..5cd14a4e778b06d96e6b989bb6e90c87511253fd 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmpssnd" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmpssnd" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmpssnd \- Network send for presentation state viewer
@@ -84,4 +84,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmpsrcv\fP(1), \fBstorescu\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1998-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1998-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index f33f1ff7efffefee8e7ca3a337045343b98798b8..a1abbcd66a11c48899fb8b48a1f0a192d51ed01d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmqridx" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmqridx" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmqridx \- Register a DICOM image file in an image database index file
@@ -85,4 +85,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmqrscp\fP(1), \fBdcmqrti\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1993-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1993-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 3e2ff98206aa6b372e3c3ed4b296f107291e3a72..3ba26be90b225c440357af1c4bc929aa12363f97 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmqrscp" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmqrscp" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmqrscp \- DICOM image archive (central test node)
@@ -172,6 +172,17 @@ restriction of query/retrieve models:
 .SS "network options"
 .PP
 .nf
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profiles from configuration file:
 
   -xf   --assoc-config-file
@@ -865,6 +876,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -1012,6 +1025,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -1076,7 +1090,7 @@ Query/Retrieve Level: PATIENT (or STUDY for the Study Root Q/R model)
 (0010,0040) PatientSex
 (0010,1000) OtherPatientIDs (retired)
 (0010,1001) OtherPatientNames
-(0010,2160) EthnicGroup
+(0010,2160) EthnicGroup (retired)
 (0010,4000) PatientComments
 .fi
 .PP
@@ -1099,7 +1113,7 @@ Query/Retrieve Level: STUDY
 (0010,21B0) AdditionalPatientHistory
 (0020,000D) StudyInstanceUID
 (0020,0010) StudyID
-(0020,1070) RETIRED_OtherStudyNumbers
+(0020,1070) OtherStudyNumbers (retired)
 .fi
 .PP
 .PP
@@ -1160,4 +1174,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBdcmqridx\fP(1), \fBdcmqrti\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1993-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1993-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index b9d8c55e3b9b6d170261fc1fa866f449c3c7dce0..423c55efb52a6d4e0832d63de312fbcff3e9eac6 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmqrti" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmqrti" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmqrti \- The Terminal Initiator Telnet Client Program
@@ -324,4 +324,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmqrscp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1993-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1993-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index d0838d1029730ed667a17235f475f6bb022b1313..5f2e8892767a2aaaf42125865574a987cb6099b3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmquant" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmquant" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmquant \- Convert DICOM color images to palette color
@@ -243,4 +243,4 @@ The \fBdcmquant\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2001-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2001-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 41d89d2e1c5d09eb1edfb444c126adc02bdb32fd..5198d3ef60c12f1b7a24a1f4a4de6b4552ecb5d5 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmrecv" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmrecv" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmrecv \- Simple DICOM storage SCP (receiver)
@@ -57,6 +57,17 @@ port  tcp/ip port number to listen on
 .SS "network options"
 .PP
 .nf
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profile from configuration file:
 
   -xf   --config-file  [f]ilename, [p]rofile: string
@@ -409,4 +420,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmsend\fP(1), \fBstorescu\fP(1), \fBstorescp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2013-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2013-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 68bd60403cc6812713a262c275bb18fcd76cbfd0..3b8c383c75f0a77c09a866eeb38f932e3856cfa2 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmscale" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmscale" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmscale \- Scale DICOM images
@@ -229,4 +229,4 @@ The \fBdcmscale\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2002-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2002-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 7a366b042b4159613e6f9daaf7681754c441bc8f..6866e924ac705ea925acfe8d1cda50d748f7c90f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmsend" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmsend" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmsend \- Simple DICOM storage SCU (sender)
@@ -328,4 +328,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmrecv\fP(1), \fBstorescu\fP(1), \fBstorescp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2011-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2011-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index b60dfed1d19b89455da1bcb60fbcb360deed7bd5..3e1d382eaa028dba81321b82dd14971dd8eefe70 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcmsign" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcmsign" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcmsign \- Sign and Verify DICOM Files
@@ -496,4 +496,4 @@ The \fBdcmsign\fP utility will attempt to load DICOM data dictionaries specified
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2000-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2000-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 64d3b9db3d15ad0a00fdb9bc7b384a1ca08974d1..50ea71ae07bac3bd92364d3b2f152297bd7cd4ab 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dcod2lum" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dcod2lum" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dcod2lum \- Convert hardcopy characteristic curve file to softcopy format
@@ -47,4 +47,4 @@ The format of both input and output file is described the documentation of the \
 \fBdcmdspfn\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2002-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2002-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 618e50e35113a6cd72918b37589feae544cb4e94..677511bc34cb839ea47ecb10f2898d863f042f72 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dconvlum" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dconvlum" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dconvlum \- Convert VeriLUM files to DCMTK display files
@@ -34,4 +34,4 @@ See DICOM standard part 14 for more details on display calibration and Barten's
 \fBdcmdspfn\fP(1), \fBdcm2pnm\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1999-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1999-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 44acad901a4728333fd2c9551432d55d25940ebc..2ee6ad06251a59e47826b2e6664c6205847ae7ec 100644 (file)
@@ -1,4 +1,4 @@
-.TH "drtdump" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "drtdump" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 drtdump \- Dump DICOM RT file and data set
@@ -132,4 +132,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmconv\fP(1), \fBdcmdump\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2010-2024 by OFFIS e\&.V\&. and ICSMED AG, Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2010-2025 by OFFIS e\&.V\&. and ICSMED AG, Escherweg 2, 26121 Oldenburg, Germany\&.
index ac984eb0096f580d3bcc92aa7f0e8420baca239b..84bbc74202aba234a2925d3fd73079d98ae1c1ef 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dsr2html" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dsr2html" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dsr2html \- Render DICOM SR file and data set to HTML/XHTML
@@ -250,8 +250,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 .fi
 .PP
+.PP
+(*) This is not a Storage SOP Class, but used for Real-Time Communication\&.
 .SS "Character Encoding"
 The HTML/XHTML encoding is determined automatically from the DICOM attribute (0008,0005) 'Specific Character Set' using the following mapping:
 .PP
@@ -281,6 +285,8 @@ Chinese       "GBK"                            =>  "GBK"
 If this DICOM attribute is missing in the input file, although needed, option \fI--charset-assume\fP can be used to specify an appropriate character set manually (using one of the DICOM defined terms)\&. For reasons of backward compatibility with previous versions of this tool, the following terms are also supported and mapped automatically to the associated DICOM defined terms: latin-1, latin-2, latin-3, latin-4, latin-5, latin-9, cyrillic, arabic, greek, hebrew\&.
 .PP
 Option \fI--convert-to-utf8\fP can be used to convert the DICOM file or data set to UTF-8 encoding prior to the rendering to HTML/XHTML format\&.
+.SS "Security"
+Please note that using one of the options \fI--css-reference\fP, \fI--css-file\fP or \fI--hyperlink-url-prefix\fP can lead to security issues, as an attacker could misuse them to potentially inject dangerous content into the HTML/XHTML output\&. The values passed to these options are not checked, neither the URL and prefix nor the content of the specified CSS file\&.
 .SH "LOGGING"
 .PP
 The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
@@ -304,10 +310,12 @@ Depending on the command line options specified, the \fBdsr2html\fP utility will
 The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICONVPATH\fP environment variable can be used to specify a different location\&. If a different location is specified, those mapping tables also replace any built-in tables\&.
 .SH "FILES"
 .PP
-\fI<datadir>/report\&.css\fP - Sample Cascading Stylesheet file for HTML \fI<datadir>/reportx\&.css\fP - Sample Cascading Stylesheet file for XHTML
+\fI<datadir>/report\&.css\fP - Sample Cascading Stylesheet file for HTML
+.br
+\fI<datadir>/reportx\&.css\fP - Sample Cascading Stylesheet file for XHTML
 .SH "SEE ALSO"
 .PP
 \fBdcmconv\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2000-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2000-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index d3b43f4917d7bdaf1bb6041992c80903071c61e2..7eaa8dda7f41371b38a63c515316d35a3456c68a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dsr2xml" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dsr2xml" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dsr2xml \- Convert DICOM SR file and data set to XML
@@ -211,9 +211,13 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 .fi
 .PP
 .PP
+(*) This is not a Storage SOP Class, but used for Real-Time Communication\&.
+.PP
 Please note that currently only mandatory and some optional attributes are supported\&.
 .SS "Character Encoding"
 The XML encoding is determined automatically from the DICOM attribute (0008,0005) 'Specific Character Set' using the following mapping:
@@ -279,4 +283,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBxml2dsr\fP(1), \fBdcmconv\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2000-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2000-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 10ced1a8272ded5a1ef5c75bc1612d318d2f17c1..c21a6143fb7cb9d9215be1368dbc6184c1a0f8b2 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dsrdump" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dsrdump" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dsrdump \- Dump DICOM SR file and data set
@@ -219,8 +219,12 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 .fi
 .PP
+.PP
+(*) This is not a Storage SOP Class, but used for Real-Time Communication\&.
 .SH "LOGGING"
 .PP
 The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
@@ -247,4 +251,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBdcmconv\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2000-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2000-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 60972d4c487ebbeebea64e98ca0c06aece0fe721..0940e0b77e3cb00880541ed42e8048adaa83e6ca 100644 (file)
@@ -1,4 +1,4 @@
-.TH "dump2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "dump2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 dump2dcm \- Convert ASCII dump to DICOM file
@@ -265,4 +265,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcmdump\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1996-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1996-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 0693752ccbe5cdcc15d09d1a183556d35dee3df6..cdcd9ed60eca4dce3c09c7f330e644ed96547b09 100644 (file)
@@ -1,4 +1,4 @@
-.TH "echoscu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "echoscu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 echoscu \- DICOM verification (C-ECHO) SCU
@@ -77,7 +77,7 @@ application entity titles:
 
 association negotiation debugging:
 
-  -pts  --propose-ts  [n]umber: integer (1..52)
+  -pts  --propose-ts  [n]umber: integer (1..53)
           propose n transfer syntaxes
 
   -ppc  --propose-pc  [n]umber: integer (1..128)
@@ -366,4 +366,4 @@ The \fBechoscu\fP utility will attempt to load DICOM data dictionaries specified
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1994-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1994-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 14a5dacdd142c02b3c99088dec73851f7cb2913f..55c88c76ecb6823f36c8bf022c44094df93b2be0 100644 (file)
@@ -1,4 +1,4 @@
-.TH "findscu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "findscu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 findscu \- DICOM query (C-FIND) SCU
@@ -425,4 +425,4 @@ The mapping table files are expected in DCMTK's \fI<datadir>\fP\&. The \fIDCMICO
 \fBmovescu\fP(1), \fBdump2dcm\fP(1), \fBdcmodify\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1994-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1994-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 0b501ee55dfd15424782ac3496cd8420a7789f50..6f84657b13024503048712b0700e8a748b35cc3d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "getscu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "getscu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 getscu \- DICOM retrieve (C-GET) SCU
@@ -449,6 +449,8 @@ BasicVoiceAudioWaveformStorage                       1.2.840.10008.5.1.4.1.1.9.4
 GeneralAudioWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.4.2
 ArterialPulseWaveformStorage                         1.2.840.10008.5.1.4.1.1.9.5.1
 RespiratoryWaveformStorage                           1.2.840.10008.5.1.4.1.1.9.6.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -606,4 +608,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBfindscu\fP(1), \fBmovescu\fP(1), \fBdump2dcm\fP(1), \fBdcmodify\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2011-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2011-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index b92286cfc43580b3fa95f1d7dc7e1c89167e4781..a59239edd5a0bc67affc3ae836adcbcccf4d1f0d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "img2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "img2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 img2dcm \- Convert standard image formats into DICOM format
@@ -314,7 +314,7 @@ Color and grayscale images are supported\&. CP-1843 enforce that the value of Pl
 .PP
 For DICOM it is clear that SPIFF header should not be present in the DICOM object's internal JPEG-LS stream\&. The plugin will simply rejects any input JPEG-LS file containing a SPIFF header at marker APP8\&.
 .PP
-By default, all APPn markers are cut off from the original JPEG-LS stream\&. However, if you want to keep APPn markers (e\&.g\&. APP8/HP color transform information, aka 'mrfx') inside the DICOM stream, the option \fI--keep-appn\fP does the trick\&. Pay attention that the plugin will check the actual color transform specified in the APP8/HP marker\&. Since DICOM does not allow any color transform to be specified in the APP8 marker, only a value of \fC0\fP (no color transform) is accepted\&.
+By default, all APPn markers are cut off from the original JPEG-LS stream\&. However, if you want to keep APPn markers (e\&.g\&. APP8/HP color transform information, aka 'mrfx') inside the DICOM stream, the option \fI--keep-appn\fP does the trick\&. Pay attention that the plugin will check the actual color transform specified in the APP8/HP marker\&. Since DICOM does not allow any color transform to be specified in the APP8 marker, only a value of 0 (no color transform) is accepted\&.
 .SS "BMP Input Plugin"
 \fBimg2dcm\fP supports BMP as input format\&. However, so far only the most common BMP images are supported\&. In particular, BMP images which use bit fields or run length encoding will be rejected\&. Such images are uncommon\&. Input images will either be converted into a DICOM image with RGB color model and a bit depth of 24, or into an image with MONOCHROME2 color model an 8 bits per pixel\&. There are no specific options for fine-tuning BMP format conversion\&.
 .SS "Output Plugins"
@@ -387,4 +387,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcm2pnm\fP(1), \fBdcmj2pnm\fP(1), \fBdump2dcm\fP(1), \fBdcmconv\fP(1), \fBdcmodify\fP(1), \fBdcm2xml\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2007-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2007-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
diff --git a/doxygen/manpages/man1/json2dcm.1 b/doxygen/manpages/man1/json2dcm.1
new file mode 100644 (file)
index 0000000..128d3e0
--- /dev/null
@@ -0,0 +1,398 @@
+.TH "json2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
+.nh
+.SH NAME
+json2dcm \- Convert JSON document to DICOM file or data set
+
+.SH "SYNOPSIS"
+.PP
+.PP
+.nf
+json2dcm [options] jsonfile-in dcmfile-out
+.fi
+.PP
+.SH "DESCRIPTION"
+.PP
+The \fBjson2dcm\fP utility converts the contents of a JSON (JavaScript Object Notation) document to a binary DICOM file or data set\&. The JSON document is expected to conform to the 'DICOM JSON Model' as defined in DICOM Part 18 Section F\&. Such JSON files can be created, e\&.g\&., using the \fBdcm2json\fP tool\&.
+.SH "PARAMETERS"
+.PP
+.PP
+.nf
+jsonfile-in  JSON input filename to be converted ("-" for stdin)
+
+dcmfile-out  DICOM output filename ("-" for stdout)
+.fi
+.PP
+.SH "OPTIONS"
+.PP
+.SS "general options"
+.PP
+.nf
+  -h   --help
+         print this help text and exit
+
+       --version
+         print version information and exit
+
+       --arguments
+         print expanded command line arguments
+
+  -q   --quiet
+         quiet mode, print no warnings and errors
+
+  -v   --verbose
+         verbose mode, print processing details
+
+  -d   --debug
+         debug mode, print debug information
+
+  -ll  --log-level  [l]evel: string constant
+         (fatal, error, warn, info, debug, trace)
+         use level l for the logger
+
+  -lc  --log-config  [f]ilename: string
+         use config file f for the logger
+.fi
+.PP
+.SS "input options"
+.PP
+.nf
+input file format:
+
+  +f   --read-meta-info
+         read meta information if present (default)
+
+  -f   --ignore-meta-info
+         ignore file meta information
+.fi
+.PP
+.SS "processing options"
+.PP
+.nf
+unique identifiers:
+
+  +Ug  --generate-new-uids
+         generate new Study/Series/SOP Instance UID
+
+  -Uo  --dont-overwrite-uids
+         do not overwrite existing UIDs (default)
+
+  +Uo  --overwrite-uids
+         overwrite existing UIDs
+
+bulkdata URI handling:
+
+  +Bu  --parse-bulkdata-uri
+         parse Bulkdata URIs (default)
+
+  -Bu  --ignore-bulkdata-uri
+         ignore Bulkdata URIs
+
+  +Bd  --add-bulkdata-dir  [d]irectory: string
+         add d to list of permitted bulk data sources
+
+handling of arrays with multiple data sets:
+
+  -ar  --array-reject
+         reject multiple data sets (default)
+
+  +as  --array-select  [n]umber: integer
+         select data set n from array
+
+  +ar  --array-sequence
+         store all data sets in private sequence
+.fi
+.PP
+.SS "output options"
+.PP
+.nf
+output file format:
+
+  +F   --write-file
+         write file format (default)
+
+  -F   --write-dataset
+         write data set without file meta information
+
+  +Fu  --update-meta-info
+         update particular file meta information
+
+output transfer syntax:
+
+  +t=  --write-xfer-same
+         write with same TS as input (default)
+
+  +te  --write-xfer-little
+         write with explicit VR little endian TS
+
+  +tb  --write-xfer-big
+         write with explicit VR big endian TS
+
+  +ti  --write-xfer-implicit
+         write with implicit VR little endian TS
+
+  +td  --write-xfer-deflated
+         write with deflated explicit VR little endian TS
+
+error handling:
+
+  -E   --stop-on-error
+         do not write if document is invalid (default)
+
+  +E   --ignore-errors
+         attempt to write even if document is invalid
+
+post-1993 value representations:
+
+  +u   --enable-new-vr
+         enable support for new VRs (UN/UT) (default)
+
+  -u   --disable-new-vr
+         disable support for new VRs, convert to OB
+
+length encoding in sequences and items:
+
+  +e   --length-explicit
+         write with explicit lengths (default)
+
+  -e   --length-undefined
+         write with undefined lengths
+
+charset handling:
+
+  +c   --charset-accept
+         write with the given charset in JSON (default)
+
+  -c   --charset-replace
+         replace the given charset in JSON with UTF-8
+
+deflate compression level (only with --write-xfer-deflated):
+
+  +cl  --compression-level  [l]evel: integer (default: 6)
+         0=uncompressed, 1=fastest, 9=best compression
+.fi
+.PP
+.SH "NOTES"
+.PP
+The basic structure of the JSON input expected looks like the following (see DICOM Part 18 Section F for details):
+.PP
+.PP
+.nf
+{
+    "00080005": {
+        "vr": "CS",
+        "Value": [
+            "ISO_IR 192"
+        ]
+    },
+    "00080020": {
+        "vr": "DT",
+        "Value": [
+            "20130409"
+        ]
+    },
+    "00080030": {
+        "vr": "TM",
+        "Value": [
+            "131600.0000"
+        ]
+    },
+    "00080050": {
+        "vr": "SH",
+        "Value": [
+            "11235813"
+        ]
+    },
+    "00080056": {
+        "vr": "CS",
+        "Value": [
+            "ONLINE"
+        ]
+    },
+    "00080061": {
+        "vr": "CS",
+        "Value": [
+            "CT",
+            "PET"
+        ]
+    },
+    "00080090": {
+        "vr": "PN",
+        "Value": [
+          {
+            "Alphabetic": "^Bob^^Dr."
+          }
+        ]
+    },
+    "00081190": {
+        "vr": "UR",
+        "Value": [
+            "http://wado.nema.org/studies/
+            1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
+        ]
+    },
+    "00090010": {
+        "vr": "LO",
+        "Value": [
+            "Vendor A"
+        ]
+    },
+    "00091002": {
+        "vr": "UN",
+        "InlineBinary": "z0x9c8v7"
+    },
+    "00100010": {
+        "vr": "PN",
+        "Value": [
+          {
+            "Alphabetic": "Wang^XiaoDong"
+          }
+        ]
+    },
+    "00100020": {
+        "vr": "LO",
+        "Value": [
+            "12345"
+        ]
+    },
+    "00100021": {
+        "vr": "LO",
+        "Value": [
+            "Hospital A"
+        ]
+    },
+    "00100030": {
+        "vr": "DA",
+        "Value": [
+            "19670701"
+        ]
+    },
+    "00100040": {
+        "vr": "CS",
+        "Value": [
+            "M"
+        ]
+    },
+    "00101002": {
+        "vr": "SQ",
+        "Value": [
+            {
+                "00100020": {
+                    "vr": "LO",
+                    "Value": [
+                        "54321"
+                    ]
+                },
+                "00100021": {
+                    "vr": "LO",
+                    "Value": [
+                        "Hospital B"
+                    ]
+                }
+            },
+            {
+                "00100020": {
+                    "vr": "LO",
+                    "Value": [
+                        "24680"
+                    ]
+                },
+                "00100021": {
+                    "vr": "LO",
+                    "Value": [
+                        "Hospital C"
+                    ]
+                }
+            }
+        ]
+    },
+    "0020000D": {
+        "vr": "UI",
+        "Value": [
+            "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
+        ]
+    },
+    "00200010": {
+        "vr": "SH",
+        "Value": [
+            "11235813"
+        ]
+    },
+    "00201206": {
+        "vr": "IS",
+        "Value": [
+            4
+        ]
+    },
+    "00201208": {
+        "vr": "IS",
+        "Value": [
+            942
+        ]
+    }
+}
+.fi
+.PP
+.SS "Character Encoding"
+The JSON format only supports UTF-8 encoding\&. Thus the generated DICOM file will also contain UTF-8 encoding\&. If the JSON file does not contain a specific character set, or a specific character set other than 'ISO_IR 192', a warning will be issued\&.
+.SS "Binary Data, Bulk Data, and Pixel Data"
+The DICOM JSON Model uses 'InlineBinary' to store attribute values of binary value representations such as 'OB', 'OW', 'OD', 'OF', 'OL', 'OV' etc\&. in Base64 encoded form\&. This is supported in \fBjson2dcm\fP for all binary attributes, including unencapsulated pixel data\&.
+.PP
+The DICOM JSON Model also permits attribute values to be stored separately from the JSON data set and to be referenced through a BulkDataURI\&. This is supported for file URIs that reference files in the local filesystem\&. \fBjson2dcm\fP tool also supports the inofficial extension to the file URI scheme generated by \fIDCM4CHE\fP, where parameters named 'offset' and 'length' are appended to the file URI in order to refer to a specific part of a file\&. HTTP URIs as well as URIs that identify another part in a MIME multipart/related structure are not yet supported in \fBjson2dcm\fP\&. If the command line option \fI--ignore-bulkdata-uri\fP is specified, then all bulk data URIs are ignored and attributes with bulk data will be written with empty value\&.
+.PP
+Finally, encapsulated (in particular, compressed) pixel data is not supported by \fBjson2dcm\fP because the syntax of the DICOM JSON Model for this specific case is not defined in the DICOM standard yet\&.
+.SS "Arrays of Data Sets"
+The DICOM JSON Model uses a JSON array structure to return multiple data sets in DICOMweb services such as WADO-RS or QIDO-RS\&. JSON arrays containing a single DICOM data set are automatically recognized by \fBjson2dcm\fP and treated like a data set without the surrounding array structure\&. JSON arrays containing multiple data sets are rejected by default\&. Alternatively, the \fI--array-select\fP option can be used to select one data set from the array to be converted\&. The \fI--array-sequence\fP option causes all data sets to be written as sequence items into a single private sequence with attribute tag (0009,1000)\&. Such files, which are mostly intended for debugging purposes, can be recognized by the private creator element (0009,0010), which has the value 'JSON2DCM_LIST_OF_DATASETS'\&.
+.SS "Trailing Commas"
+Trailing commas are not permitted in JSON, but \fBjson2dcm\fP will still accept such JSON data sets without warning or error message because they are handled gracefully by the underlying JSON parser\&. Users should, therefore, not assume that a JSON data set is valid just because \fBjson2dcm\fP accepts it\&. This tool is not designed as a validator for JSON or the DICOM JSON Model\&.
+.SH "LOGGING"
+.PP
+The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
+.PP
+In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
+.SH "COMMAND LINE"
+.PP
+All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
+.PP
+Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
+.PP
+In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
+.SH "EXIT CODES"
+.PP
+The \fBdcm2json\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
+.SS "general"
+.PP
+.nf
+EXITCODE_NO_ERROR                               0
+EXITCODE_COMMANDLINE_SYNTAX_ERROR               1
+.fi
+.PP
+.SS "input file errors"
+.PP
+.nf
+EXITCODE_CANNOT_READ_INPUT_FILE                 20
+.fi
+.PP
+.SS "output file errors"
+.PP
+.nf
+EXITCODE_CANNOT_WRITE_OUTPUT_FILE               40
+.fi
+.PP
+.SS "processing errors"
+.PP
+.nf
+EXITCODE_INVALID_JSON_CONTENT                   65
+EXITCODE_BULKDATA_URI_NOT_SUPPORTED             66
+.fi
+.PP
+.SH "ENVIRONMENT"
+.PP
+The \fBjson2dcm\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
+.PP
+The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+.SH "SEE ALSO"
+.PP
+\fBdcm2json\fP(1) \fBdump2dcm\fP(2)
+.SH "COPYRIGHT"
+.PP
+Copyright (C) 2024-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 39de1458b3cbcbb553852077c3e8660b61d47af0..976740f666a1c7d2bd7c90f2787aa872dc325222 100644 (file)
@@ -1,4 +1,4 @@
-.TH "mkcsmapper" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "mkcsmapper" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 mkcsmapper \- Create csmapper conversion files for oficonv
index f6223e1dc9a2340bb55f25409e04e3f7063c7fb7..45bf1b6f9dd1466baf6595e63c95a5990c239944 100644 (file)
@@ -1,4 +1,4 @@
-.TH "mkesdb" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "mkesdb" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 mkesdb \- Create encoding scheme database (esdb) files for oficonv
index cedf4e26e6d1837219affe9683a920dfce3564cb..f6dc7237542a141c6b40075a9cfbfe12a8dc55d9 100644 (file)
@@ -1,4 +1,4 @@
-.TH "movescu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "movescu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 movescu \- DICOM retrieve (C-MOVE) SCU
@@ -58,6 +58,17 @@ dcmfile-in  DICOM query file(s)
 .SS "network options"
 .PP
 .nf
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 override matching keys:
 
   -k    --key  [k]ey: gggg,eeee="str" or dictionary name="str"
@@ -232,6 +243,131 @@ other network options:
           silently correct space-padded UIDs
 .fi
 .PP
+.SS "transport layer security (TLS) options"
+.PP
+.nf
+transport protocol stack:
+
+  -tls  --disable-tls
+          use normal TCP/IP connection (default)
+
+  +tls  --enable-tls  [p]rivate key file, [c]ertificate file: string
+          use authenticated secure TLS connection
+
+private key password (only with --enable-tls):
+
+  +ps   --std-passwd
+          prompt user to type password on stdin (default)
+
+  +pw   --use-passwd  [p]assword: string
+          use specified password
+
+  -pw   --null-passwd
+          use empty string as password
+
+key and certificate file format:
+
+  -pem  --pem-keys
+          read keys and certificates as PEM file (default)
+
+  -der  --der-keys
+          read keys and certificates as DER file
+
+certification authority:
+
+  +cf   --add-cert-file  [f]ilename: string
+          add certificate file to list of certificates
+
+  +cd   --add-cert-dir  [d]irectory: string
+          add certificates in d to list of certificates
+
+  +crl  --add-crl-file  [f]ilename: string
+          add certificate revocation list file
+          (implies --enable-crl-vfy)
+
+  +crv  --enable-crl-vfy
+          enable leaf CRL verification
+
+  +cra  --enable-crl-all
+          enable full chain CRL verification
+
+security profile:
+
+  +ph   --list-profiles
+          list supported TLS profiles and exit
+
+  +pg   --profile-8996
+          BCP 195 RFC 8996 TLS Profile (default)
+
+  +pm   --profile-8996-mod
+          Modified BCP 195 RFC 8996 TLS Profile
+
+          # only available if underlying TLS library supports
+          # all TLS features required for this profile
+
+  +py   --profile-bcp195-nd
+          Non-downgrading BCP 195 TLS Profile (retired)
+
+  +px   --profile-bcp195
+          BCP 195 TLS Profile (retired)
+
+  +pz   --profile-bcp195-ex
+          Extended BCP 195 TLS Profile (retired)
+
+  +pb   --profile-basic
+          Basic TLS Secure Transport Connection Profile (retired)
+
+          # only available if underlying TLS library supports 3DES
+
+  +pa   --profile-aes
+          AES TLS Secure Transport Connection Profile (retired)
+
+  +pn   --profile-null
+          Authenticated unencrypted communication
+          (retired, was used in IHE ATNA)
+
+ciphersuite:
+
+  +cc   --list-ciphers
+          list supported TLS ciphersuites and exit
+
+  +cs   --cipher  [c]iphersuite name: string
+          add ciphersuite to list of negotiated suites
+
+  +dp   --dhparam  [f]ilename: string
+          read DH parameters for DH/DSS ciphersuites
+
+server name indication:
+
+        --no-sni
+          do not use SNI (default)
+
+        --expect-sni  [s]erver name: string
+          expect requests for server name s
+
+pseudo random generator:
+
+  +rs   --seed  [f]ilename: string
+          seed random generator with contents of f
+
+  +ws   --write-seed
+          write back modified seed (only with --seed)
+
+  +wf   --write-seed-file  [f]ilename: string (only with --seed)
+          write modified seed to file f
+
+peer authentication:
+
+  -rc   --require-peer-cert
+          verify peer certificate, fail if absent (default)
+
+  -vc   --verify-peer-cert
+          verify peer certificate if present
+
+  -ic   --ignore-peer-cert
+          don't verify peer certificate
+.fi
+.PP
 .SS "output options"
 .PP
 .nf
@@ -444,6 +580,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -591,6 +729,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -646,6 +785,7 @@ HighThroughputJPEG2000ImageCompressionLossless.Tr.S. 1.2.840.10008.1.2.4.201
 HighThroughputJPEG2000RPCLImageCompressionLoss.Tr.S. 1.2.840.10008.1.2.4.202
 HighThroughputJPEG2000ImageCompressionTransferSynta. 1.2.840.10008.1.2.4.203
 RLELosslessTransferSyntax                            1.2.840.10008.1.2.5
+DeflatedImageFrameCompressionTransferSyntax          1.2.840.10008.1.2.8.1
 .fi
 .PP
 .PP
@@ -706,6 +846,7 @@ EXITCODE_NO_PRESENTATION_CONTEXT         66
 EXITCODE_CANNOT_CLOSE_ASSOCIATION        67
 EXITCODE_CMOVE_WARNING                   68
 EXITCODE_CMOVE_ERROR                     69
+EXITCODE_CANNOT_CREATE_TLS_LAYER         70
 .fi
 .PP
 .SH "ENVIRONMENT"
@@ -718,4 +859,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBfindscu\fP(1), \fBstorescp\fP(1), \fBdump2dcm\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1994-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1994-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 6dc700d14d79b77ead549317b9af1598e84dcae9..d59c1633fc708eb4abfdbffdca247e4f3186a2e3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "pdf2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "pdf2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 pdf2dcm \- Encapsulate PDF file into DICOM file format
@@ -12,214 +12,10 @@ pdf2dcm [options] pdffile-in dcmfile-out
 .PP
 .SH "DESCRIPTION"
 .PP
-The \fBpdf2dcm\fP utility reads a PDF file (\fIpdffile-in\fP), converts it to a DICOM Encapsulated PDF Storage SOP instance and stores the converted data to an output file (\fIdcmfile-out\fP)\&.
-.SH "PARAMETERS"
-.PP
-.PP
-.nf
-pdffile-in   PDF input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-.fi
-.PP
-.SH "OPTIONS"
-.PP
-.SS "general options"
-.PP
-.nf
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-.fi
-.PP
-.SS "DICOM document options"
-.PP
-.nf
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-.fi
-.PP
-.SS "processing options"
-.PP
-.nf
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-.fi
-.PP
-.SS "output options"
-.PP
-.nf
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-.fi
-.PP
-.SH "NOTES"
-.PP
-.SS "Attribute Sources"
-The application may be fed with some additional input for filling mandatory (and optional) attributes in the new DICOM file like patient, study and series information:
-.PP
-.IP "\(bu" 2
-The \fI--key\fP option can be used to add further attributes to the DICOM output file\&.
-.IP "\(bu" 2
-It is also possible to specify sequences, items and nested attributes using the \fI--key\fP option\&. In these cases, a special 'path' notation has to be used\&. Details on this path notation can be found in the documentation of \fBdcmodify\fP\&.
-.IP "\(bu" 2
-The \fI--key\fP option can be present more than once\&.
-.IP "\(bu" 2
-The value part (after the '=') may be absent causing the attribute to be set with zero length\&.
-.IP "\(bu" 2
-Please be advised that the \fI--key\fP option is applied at the very end, just before saving the DICOM file, so there is no value checking whatsoever\&.
-.PP
-.SH "LOGGING"
-.PP
-The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
-.PP
-In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
-.SH "COMMAND LINE"
-.PP
-All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
-.PP
-Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
-.PP
-In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
-.SH "EXIT CODES"
-.PP
-The \fBpdf2dcm\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
-.SS "general"
-.PP
-.nf
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-.fi
-.PP
-.SS "input file errors"
-.PP
-.nf
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-.fi
-.PP
-.SS "output file errors"
-.PP
-.nf
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-.fi
-.PP
-.SH "ENVIRONMENT"
-.PP
-The \fBpdf2dcm\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
-.PP
-The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+The \fBpdf2dcm\fP tool is deprecated\&. Use \fBdcmencap\fP instead, which supports the same command line parameters, and more\&.
 .SH "SEE ALSO"
 .PP
-\fBdcm2pdf\fP(1)
+\fBdcmencap\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2005-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2005-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 49db5cc95d2215d5e380ab9931cc34ce2b0914bf..24e3e3ed2027d0afa9825988d1c54c52a507ed1d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "stl2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "stl2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 stl2dcm \- Encapsulate STL file into DICOM file format
@@ -12,231 +12,10 @@ stl2dcm [options] stlfile-in dcmfile-out
 .PP
 .SH "DESCRIPTION"
 .PP
-The \fBstl2dcm\fP utility reads a STL file (\fIstlfile-in\fP), converts it to a DICOM Encapsulated STL Storage SOP instance and stores the converted data to an output file (\fIdcmfile-out\fP)\&.
-.SH "PARAMETERS"
+The \fBstl2dcm\fP tool is deprecated\&. Use \fBdcmencap\fP instead, which supports the same command line parameters, and more\&.
+.SH "SEE ALSO"
 .PP
-.PP
-.nf
-stlfile-in   STL input filename to be encapsulated
-
-dcmfile-out  DICOM output filename ("-" for stdout)
-.fi
-.PP
-.SH "OPTIONS"
-.PP
-.SS "general options"
-.PP
-.nf
-  -h   --help
-         print this help text and exit
-
-       --version
-         print version information and exit
-
-       --arguments
-         print expanded command line arguments
-
-  -q   --quiet
-         quiet mode, print no warnings and errors
-
-  -v   --verbose
-         verbose mode, print processing details
-
-  -d   --debug
-         debug mode, print debug information
-
-  -ll  --log-level  [l]evel: string constant
-         (fatal, error, warn, info, debug, trace)
-         use level l for the logger
-
-  -lc  --log-config  [f]ilename: string
-         use config file f for the logger
-.fi
-.PP
-.SS "DICOM document options"
-.PP
-.nf
-document title:
-
-  +t   --title  [t]itle: string (default: empty)
-         document title
-
-  +cn  --concept-name  [CSD] [CV] [CM]: string (default: empty)
-         coded representation of document title defined by coding
-         scheme designator CSD, code value CV and code meaning CM
-
-patient data:
-
-  +pn  --patient-name  [n]ame: string
-         patient's name in DICOM PN syntax
-
-  +pi  --patient-id  [i]d: string
-         patient identifier
-
-  +pb  --patient-birthdate  [d]ate: string (YYYYMMDD)
-         patient's birth date
-
-  +ps  --patient-sex  [s]ex: string (M, F or O)
-         patient's sex
-
-study and series:
-
-  +sg  --generate
-         generate new study and series UIDs (default)
-
-  +st  --study-from  [f]ilename: string
-         read patient/study data from DICOM file
-
-  +se  --series-from  [f]ilename: string
-         read patient/study/series data from DICOM file
-
-instance number:
-
-  +i1  --instance-one
-         use instance number 1 (default, not with +se)
-
-  +ii  --instance-inc
-         increment instance number (only with +se)
-
-  +is  --instance-set [i]nstance number: integer
-         use instance number i
-
-burned-in annotation:
-
-  +an  --annotation-yes
-         document contains patient identifying data (default)
-
-  -an  --annotation-no
-         document does not contain patient identifying data
-
-enhanced general equipment:
-
-  +mn  --manufacturer  [n]ame: string
-         manufacturer's name
-
-  +mm  --manufacturer-model  [n]ame: string
-         manufacturer's model name
-
-  +ds  --device-serial  [n]umber: string
-         device serial number
-
-  +sv  --software-versions  [v]ersions: string
-         software versions
-
-3d model measurement units:
-
-  +mu  --measurement-units  [CSD] [CV] [CM]: string
-         measurement units with coding scheme designator CSD,
-         code value CV and code meaning CM (default: UCUM, um, um)
-.fi
-.PP
-.SS "processing options"
-.PP
-.nf
-other processing options:
-
-  -k   --key  [k]ey: gggg,eeee="str", path or dictionary name="str"
-         add further attribute
-.fi
-.PP
-.SS "output options"
-.PP
-.nf
-output file format:
-
-  +F   --write-file
-         write file format (default)
-
-  -F   --write-dataset
-         write data set without file meta information
-
-group length encoding:
-
-  +g=  --group-length-recalc
-         recalculate group lengths if present (default)
-
-  +g   --group-length-create
-         always write with group length elements
-
-  -g   --group-length-remove
-         always write without group length elements
-
-length encoding in sequences and items:
-
-  +e   --length-explicit
-         write with explicit lengths (default)
-
-  -e   --length-undefined
-         write with undefined lengths
-
-data set trailing padding (not with --write-dataset):
-
-  -p   --padding-off
-         no padding (implicit if --write-dataset)
-
-  +p   --padding-create  [f]ile-pad [i]tem-pad: integer
-         align file on multiple of f bytes
-         and items on multiple of i bytes
-.fi
-.PP
-.SH "NOTES"
-.PP
-.SS "Attribute Sources"
-The application may be fed with some additional input for filling mandatory (and optional) attributes in the new DICOM file like patient, study and series information:
-.PP
-.IP "\(bu" 2
-The \fI--key\fP option can be used to add further attributes to the DICOM output file\&.
-.IP "\(bu" 2
-It is also possible to specify sequences, items and nested attributes using the \fI--key\fP option\&. In these cases, a special 'path' notation has to be used\&. Details on this path notation can be found in the documentation of \fBdcmodify\fP\&.
-.IP "\(bu" 2
-The \fI--key\fP option can be present more than once\&.
-.IP "\(bu" 2
-The value part (after the '=') may be absent causing the attribute to be set with zero length\&.
-.IP "\(bu" 2
-Please be advised that the \fI--key\fP option is applied at the very end, just before saving the DICOM file, so there is no value checking whatsoever\&.
-.PP
-.SH "LOGGING"
-.PP
-The level of logging output of the various command line tools and underlying libraries can be specified by the user\&. By default, only errors and warnings are written to the standard error stream\&. Using option \fI--verbose\fP also informational messages like processing details are reported\&. Option \fI--debug\fP can be used to get more details on the internal activity, e\&.g\&. for debugging purposes\&. Other logging levels can be selected using option \fI--log-level\fP\&. In \fI--quiet\fP mode only fatal errors are reported\&. In such very severe error events, the application will usually terminate\&. For more details on the different logging levels, see documentation of module 'oflog'\&.
-.PP
-In case the logging output should be written to file (optionally with logfile rotation), to syslog (Unix) or the event log (Windows) option \fI--log-config\fP can be used\&. This configuration file also allows for directing only certain messages to a particular output stream and for filtering certain messages based on the module or application where they are generated\&. An example configuration file is provided in \fI<etcdir>/logger\&.cfg\fP\&.
-.SH "COMMAND LINE"
-.PP
-All command line tools use the following notation for parameters: square brackets enclose optional values (0-1), three trailing dots indicate that multiple values are allowed (1-n), a combination of both means 0 to n values\&.
-.PP
-Command line options are distinguished from parameters by a leading '+' or '-' sign, respectively\&. Usually, order and position of command line options are arbitrary (i\&.e\&. they can appear anywhere)\&. However, if options are mutually exclusive the rightmost appearance is used\&. This behavior conforms to the standard evaluation rules of common Unix shells\&.
-.PP
-In addition, one or more command files can be specified using an '@' sign as a prefix to the filename (e\&.g\&. \fI@command\&.txt\fP)\&. Such a command argument is replaced by the content of the corresponding text file (multiple whitespaces are treated as a single separator unless they appear between two quotation marks) prior to any further evaluation\&. Please note that a command file cannot contain another command file\&. This simple but effective approach allows one to summarize common combinations of options/parameters and avoids longish and confusing command lines (an example is provided in file \fI<datadir>/dumppat\&.txt\fP)\&.
-.SH "EXIT CODES"
-.PP
-The \fBstl2dcm\fP utility uses the following exit codes when terminating\&. This enables the user to check for the reason why the application terminated\&.
-.SS "general"
-.PP
-.nf
-EXITCODE_NO_ERROR                 0
-EXITCODE_COMMANDLINE_SYNTAX_ERROR 1
-EXITCODE_MEMORY_EXHAUSTED         4
-.fi
-.PP
-.SS "input file errors"
-.PP
-.nf
-EXITCODE_CANNOT_READ_INPUT_FILE   20
-EXITCODE_NO_INPUT_FILES           21
-EXITCODE_INVALID_INPUT_FILE       22
-.fi
-.PP
-.SS "output file errors"
-.PP
-.nf
-EXITCODE_CANNOT_WRITE_OUTPUT_FILE 40
-.fi
-.PP
-.SH "ENVIRONMENT"
-.PP
-The \fBstl2dcm\fP utility will attempt to load DICOM data dictionaries specified in the \fIDCMDICTPATH\fP environment variable\&. By default, i\&.e\&. if the \fIDCMDICTPATH\fP environment variable is not set, the file \fI<datadir>/dicom\&.dic\fP will be loaded unless the dictionary is built into the application (default for Windows)\&.
-.PP
-The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
+\fBdcmencap\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2018-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2018-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index daca35ebabcf339b9fe8d7d959173d53faf9e96e..8d77dc2c8e2fc5a7de7da15b1400d0b72891672a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "storescp" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "storescp" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 storescp \- DICOM storage (C-STORE) SCP
@@ -63,11 +63,25 @@ port  tcp/ip port number to listen on
 
         --fork
           fork child process for each association
+
+        --max-associations  [m]ax: integer (default: unlimited)
+          limit number of parallel associations to m
 .fi
 .PP
 .SS "network options"
 .PP
 .nf
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 association negotiation profile from configuration file:
 
   -xf   --config-file  [f]ilename [p]rofile: string
@@ -609,6 +623,8 @@ ElectromyogramWaveformStorage                        1.2.840.10008.5.1.4.1.1.9.7
 ElectrooculogramWaveformStorage                      1.2.840.10008.5.1.4.1.1.9.7.3
 SleepElectroencephalogramWaveformStorage             1.2.840.10008.5.1.4.1.1.9.7.4
 BodyPositionWaveformStorage                          1.2.840.10008.5.1.4.1.1.9.8.1
+WaveformPresentationStateStorage                     1.2.840.10008.5.1.4.1.1.9.100.1
+WaveformAcquisitionPresentationStateStorage          1.2.840.10008.5.1.4.1.1.9.100.2
 RETIRED_StandaloneModalityLUTStorage                 1.2.840.10008.5.1.4.1.1.10
 RETIRED_StandaloneVOILUTStorage                      1.2.840.10008.5.1.4.1.1.11
 GrayscaleSoftcopyPresentationStateStorage            1.2.840.10008.5.1.4.1.1.11.1
@@ -756,6 +772,7 @@ DICONDE_EddyCurrentImageStorage                      1.2.840.10008.5.1.4.1.1.601
 DICONDE_EddyCurrentMultiframeImageStorage            1.2.840.10008.5.1.4.1.1.601.2
 DICONDE_ThermographyImageStorage                     1.2.840.10008.5.1.4.1.1.601.3
 DICONDE_ThermographyMultiFrameImageStorage           1.2.840.10008.5.1.4.1.1.601.4
+DICONDE_UltrasoundWaveformStorage                    1.2.840.10008.5.1.4.1.1.601.5
 DRAFT_RTBeamsDeliveryInstructionStorage              1.2.840.10008.5.1.4.34.1
 RTBeamsDeliveryInstructionStorage                    1.2.840.10008.5.1.4.34.7
 RTBrachyApplicationSetupDeliveryInstructionStorage   1.2.840.10008.5.1.4.34.10
@@ -811,6 +828,7 @@ HighThroughputJPEG2000ImageCompressionLossless.Tr.S. 1.2.840.10008.1.2.4.201
 HighThroughputJPEG2000RPCLImageCompressionLoss.Tr.S. 1.2.840.10008.1.2.4.202
 HighThroughputJPEG2000ImageCompressionTransferSynta. 1.2.840.10008.1.2.4.203
 RLELosslessTransferSyntax                            1.2.840.10008.1.2.5
+DeflatedImageFrameCompressionTransferSyntax          1.2.840.10008.1.2.8.1
 .fi
 .PP
 .PP
@@ -863,4 +881,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBstorescu\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1996-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1996-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index cbb1ad7ccf3c931cdb53f284add6263d8878d1e5..90d8b31a3efbe6807c0b28b06a66426326181d73 100644 (file)
@@ -1,4 +1,4 @@
-.TH "storescu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "storescu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 storescu \- DICOM storage (C-STORE) SCU
@@ -562,4 +562,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBstorescp\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1996-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1996-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 139450fd92ad78e0eeff05db73c812c5defe791e..9c814d4747bef3bcd249e874b9e2fe2c86249804 100644 (file)
@@ -1,4 +1,4 @@
-.TH "termscu" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "termscu" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 termscu \- DICOM termination SCU
@@ -110,4 +110,4 @@ The \fBtermscu\fP utility will attempt to load DICOM data dictionaries specified
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2005-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2005-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 81f94afda2659a7eade0859109add1e1da4f69d6..32cad82cf273f6901d7c1c22293a96a43981ecb3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "wlmscpfs" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "wlmscpfs" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 wlmscpfs \- DICOM Basic Worklist Management SCP (based on data files)
@@ -102,6 +102,17 @@ other processing options:
 .SS "network options"
 .PP
 .nf
+IP protocol version:
+
+  -i4   --ipv4
+          use IPv4 only (default)
+
+  -i6   --ipv6
+          use IPv6 only
+
+  -i0   --ip-auto
+          use IPv6/IPv4 dual stack
+
 preferred network transfer syntaxes:
 
   +x=   --prefer-uncompr
@@ -334,7 +345,7 @@ As return keys the following attributes are currently supported by \fBwlmscpfs:\
 (0010,1080) MilitaryRank
 (0010,2000) MedicalAlerts
 (0010,2110) ContrastAllergies
-(0010,2160) EthnicGroup
+(0010,2160) EthnicGroup (retired)
 (0010,21a0) SmokingStatus
 (0010,21b0) AdditionalPatientHistory
 (0010,21c0) PregnancyStatus
@@ -421,4 +432,4 @@ The \fBwlmscpfs\fP utility will attempt to load DICOM data dictionaries specifie
 The default behavior should be preferred and the \fIDCMDICTPATH\fP environment variable only used when alternative data dictionaries are required\&. The \fIDCMDICTPATH\fP environment variable has the same format as the Unix shell \fIPATH\fP variable in that a colon (':') separates entries\&. On Windows systems, a semicolon (';') is used as a separator\&. The data dictionary code will attempt to load each file specified in the \fIDCMDICTPATH\fP environment variable\&. It is an error if no data dictionary can be loaded\&.
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 1996-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 1996-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 03075dba3d272a2f9cd5e7575fe68079e4c32181..31b2717efda279c75d8a0c20bc151a544f9cff07 100644 (file)
@@ -1,4 +1,4 @@
-.TH "xml2dcm" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "xml2dcm" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 xml2dcm \- Convert XML document to DICOM file or data set
@@ -284,4 +284,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdcm2xml\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2003-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2003-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index d3b58871103efcea1df923793d9b2e8e98013747..b19a07c99da7a2272ca2491edb58f5be932e4e13 100644 (file)
@@ -1,4 +1,4 @@
-.TH "xml2dsr" 1 "Wed Dec 11 2024" "Version 3.6.9" "OFFIS DCMTK" \" -*- nroff -*-
+.TH "xml2dsr" 1 "Mon Dec 15 2025" "Version 3.7.0" "OFFIS DCMTK" \" -*- nroff -*-
 .nh
 .SH NAME
 xml2dsr \- Convert XML document to DICOM SR file
@@ -190,9 +190,13 @@ PatientRadiationDoseSRStorage                1.2.840.10008.5.1.4.1.1.88.73
 PlannedImagingAgentAdministrationSRStorage   1.2.840.10008.5.1.4.1.1.88.74
 PerformedImagingAgentAdministrationSRStorage 1.2.840.10008.5.1.4.1.1.88.75
 WaveformAnnotationSRStorage                  1.2.840.10008.5.1.4.1.1.88.77
+
+RenditionSelectionDocumentRealTimeCommunication 1.2.840.10008.10.4 (*)
 .fi
 .PP
 .PP
+(*) This is not a Storage SOP Class, but used for Real-Time Communication\&.
+.PP
 Please note that currently only mandatory and some optional attributes are supported\&.
 .SS "Character Encoding"
 The DICOM character encoding is determined automatically from the element with tag '0008,0005' (Specific Character Set) - if present\&. The following character sets are currently supported (requires \fBlibxml\fP to include \fBiconv\fP support, see \fI--version\fP output):
@@ -250,4 +254,4 @@ The default behavior should be preferred and the \fIDCMDICTPATH\fP environment v
 \fBdsr2xml\fP(1)
 .SH "COPYRIGHT"
 .PP
-Copyright (C) 2003-2024 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
+Copyright (C) 2003-2025 by OFFIS e\&.V\&., Escherweg 2, 26121 Oldenburg, Germany\&.
index 508edd6497ced3ff6de94a819468ceac969236a3..e76300444d7c5088b03006a7da61c0d15689a98e 100644 (file)
@@ -28,9 +28,7 @@
  */
 
 #include "dcmtk/config/osconfig.h"
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
@@ -593,7 +591,7 @@ set_src_zone(uint32_t val)
                if (rowcol_len <= 32 / rowcol_bits)
                        break;
        /*FALLTHROUGH*/
-       default: 
+       default:
                goto bad;
        }
        rowcol_mask = 1u << (rowcol_bits - 1);
index 7dd4017c7ed77b586adb7cea8b25a71d9adca97b..61e007ff711c26b0abf38c26d38067669349aba7 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.  */
+/* A Bison parser, made by GNU Bison 3.8.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
    USER NAME SPACE" below.  */
 
 /* Identify Bison output, and Bison version.  */
-#define YYBISON 30705
+#define YYBISON 30802
 
 /* Bison version string.  */
-#define YYBISON_VERSION "3.7.5"
+#define YYBISON_VERSION "3.8.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -98,9 +98,7 @@
  */
 
 #include "dcmtk/config/osconfig.h"
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
@@ -303,7 +301,7 @@ static void put32(void *, size_t, uint32_t);
 static void    set_range(uint32_t, uint32_t);
 static void    set_src(linear_zone_t *, uint32_t, uint32_t);
 
-#line 307 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 305 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
 
 # ifndef YY_CAST
 #  ifdef __cplusplus
@@ -531,12 +529,18 @@ typedef int yy_state_fast_t;
 # define YY_USE(E) /* empty */
 #endif
 
-#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
+# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
+# else
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
     _Pragma ("GCC diagnostic push")                                     \
     _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# endif
 # define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
@@ -752,14 +756,14 @@ static const yytype_int8 yytranslate[] =
 };
 
 #if YYDEBUG
-  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_int16 yyrline[] =
 {
-       0,   256,   256,   259,   260,   261,   262,   263,   264,   265,
-     266,   267,   269,   270,   271,   272,   274,   275,   277,   278,
-     281,   285,   286,   287,   288,   290,   291,   293,   294,   296,
-     297,   299,   301,   303,   307,   311,   317,   320,   324,   328,
-     332,   333
+       0,   254,   254,   257,   258,   259,   260,   261,   262,   263,
+     264,   265,   267,   268,   269,   270,   272,   273,   275,   276,
+     279,   283,   284,   285,   286,   288,   289,   291,   292,   294,
+     295,   297,   299,   301,   305,   309,   315,   318,   322,   326,
+     330,   331
 };
 #endif
 
@@ -792,17 +796,6 @@ yysymbol_name (yysymbol_kind_t yysymbol)
 }
 #endif
 
-#ifdef YYPRINT
-/* YYTOKNUM[NUM] -- (External) token number corresponding to the
-   (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_int16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,    45,    47,
-      61
-};
-#endif
-
 #define YYPACT_NINF (-39)
 
 #define yypact_value_is_default(Yyn) \
@@ -813,8 +806,8 @@ static const yytype_int16 yytoknum[] =
 #define yytable_value_is_error(Yyn) \
   0
 
-  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-     STATE-NUM.  */
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
 static const yytype_int8 yypact[] =
 {
      -39,    12,    -1,   -39,     3,     4,     7,     9,    10,    11,
@@ -826,9 +819,9 @@ static const yytype_int8 yypact[] =
       14,    25,   -39
 };
 
-  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
-     Performed when YYTABLE does not specify something else to do.  Zero
-     means the default is an error.  */
+/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE does not specify something else to do.  Zero
+   means the default is an error.  */
 static const yytype_int8 yydefact[] =
 {
        3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
@@ -840,7 +833,7 @@ static const yytype_int8 yydefact[] =
       20,     0,    17
 };
 
-  /* YYPGOTO[NTERM-NUM].  */
+/* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
      -39,   -39,   -39,   -39,   -39,   -39,   -38,   -39,   -39,   -39,
@@ -848,7 +841,7 @@ static const yytype_int8 yypgoto[] =
      -39,   -20
 };
 
-  /* YYDEFGOTO[NTERM-NUM].  */
+/* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
        0,     1,     2,    13,    14,    23,    26,    58,    15,    27,
@@ -856,9 +849,9 @@ static const yytype_int8 yydefgoto[] =
       45,    32
 };
 
-  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
-     positive, shift that token.  If negative, reduce the rule whose
-     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule whose
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int8 yytable[] =
 {
       36,    47,     4,     5,     6,     7,     8,     9,    10,    33,
@@ -877,8 +870,8 @@ static const yytype_int8 yycheck[] =
       20,    19,    18,    -1,    19
 };
 
-  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-     symbol of state STATE-NUM.  */
+/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
+   state STATE-NUM.  */
 static const yytype_int8 yystos[] =
 {
        0,    22,    23,     0,     3,     4,     5,     6,     7,     8,
@@ -890,7 +883,7 @@ static const yytype_int8 yystos[] =
       16,    27,    19
 };
 
-  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
 static const yytype_int8 yyr1[] =
 {
        0,    21,    22,    23,    23,    23,    23,    23,    23,    23,
@@ -900,7 +893,7 @@ static const yytype_int8 yyr1[] =
       42,    42
 };
 
-  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
 static const yytype_int8 yyr2[] =
 {
        0,     2,     3,     0,     2,     2,     2,     2,     2,     2,
@@ -919,6 +912,7 @@ enum { YYENOMEM = -2 };
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
 #define YYERROR         goto yyerrorlab
+#define YYNOMEM         goto yyexhaustedlab
 
 
 #define YYRECOVERING()  (!!yyerrstatus)
@@ -959,10 +953,7 @@ do {                                            \
     YYFPRINTF Args;                             \
 } while (0)
 
-/* This macro is provided for backward compatibility. */
-# ifndef YY_LOCATION_PRINT
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
+
 
 
 # define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
@@ -989,10 +980,6 @@ yy_symbol_value_print (FILE *yyo,
   YY_USE (yyoutput);
   if (!yyvaluep)
     return;
-# ifdef YYPRINT
-  if (yykind < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
-# endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YY_USE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
@@ -1177,6 +1164,7 @@ yyparse (void)
   YYDPRINTF ((stderr, "Starting parse\n"));
 
   yychar = YYEMPTY; /* Cause a token to be read.  */
+
   goto yysetstate;
 
 
@@ -1202,7 +1190,7 @@ yysetstate:
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
-    goto yyexhaustedlab;
+    YYNOMEM;
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
@@ -1230,7 +1218,7 @@ yysetstate:
 # else /* defined YYSTACK_RELOCATE */
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-        goto yyexhaustedlab;
+        YYNOMEM;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
         yystacksize = YYMAXDEPTH;
@@ -1241,7 +1229,7 @@ yysetstate:
           YY_CAST (union yyalloc *,
                    YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
-          goto yyexhaustedlab;
+          YYNOMEM;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
 #  undef YYSTACK_RELOCATE
@@ -1263,6 +1251,7 @@ yysetstate:
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
+
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -1375,169 +1364,169 @@ yyreduce:
   switch (yyn)
     {
   case 2: /* file: property mapping lns  */
-#line 257 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 255 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 { dump_file(); }
-#line 1381 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1370 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 12: /* name: R_NAME L_STRING  */
-#line 269 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 267 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                   { set_name((yyvsp[0].s_value)); (yyvsp[0].s_value) = NULL; }
-#line 1387 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1376 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 13: /* type: R_TYPE types  */
-#line 270 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 268 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                { set_type((yyvsp[0].i_value)); }
-#line 1393 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1382 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 14: /* types: R_ROWCOL  */
-#line 271 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 269 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                            { (yyval.i_value) = R_ROWCOL; }
-#line 1399 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1388 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 15: /* range: L_IMM '-' L_IMM  */
-#line 272 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 270 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                   { set_range((yyvsp[-2].i_value), (yyvsp[0].i_value)); }
-#line 1405 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1394 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 18: /* src_zone: R_SRC_ZONE zone  */
-#line 277 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 275 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                   { set_src_zone((yyvsp[0].i_value)); }
-#line 1411 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1400 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 19: /* zone: range  */
-#line 278 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 276 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                         {
                        (yyval.i_value) = 32;
                }
-#line 1419 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1408 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 20: /* zone: range '/' range '/' ranges L_IMM  */
-#line 281 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 279 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                                    {
                        (yyval.i_value) = (yyvsp[0].i_value);
                }
-#line 1427 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1416 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 21: /* dst_invalid: R_DST_INVALID L_IMM  */
-#line 285 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 283 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                       { set_dst_invalid((yyvsp[0].i_value)); }
-#line 1433 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1422 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 22: /* dst_ilseq: R_DST_ILSEQ L_IMM  */
-#line 286 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 284 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                     { set_dst_ilseq((yyvsp[0].i_value)); }
-#line 1439 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1428 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 23: /* dst_unit_bits: R_DST_UNIT_BITS L_IMM  */
-#line 287 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 285 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                         { set_dst_unit_bits((yyvsp[0].i_value)); }
-#line 1445 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1434 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 24: /* oob_mode: R_OOB_MODE oob_mode_sel  */
-#line 288 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 286 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                           { set_oob_mode((yyvsp[0].i_value)); }
-#line 1451 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1440 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 25: /* oob_mode_sel: R_INVALID  */
-#line 290 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 288 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                             { (yyval.i_value) = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
-#line 1457 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1446 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 26: /* oob_mode_sel: R_ILSEQ  */
-#line 291 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 289 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                           { (yyval.i_value) = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
-#line 1463 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1452 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 28: /* begin_map: R_BEGIN_MAP lns  */
-#line 294 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 292 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                                   { setup_map(); }
-#line 1469 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1458 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 31: /* map_elem: src '=' dst  */
-#line 300 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 298 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 { store(&(yyvsp[-2].lz_value), (yyvsp[0].i_value), 0); }
-#line 1475 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1464 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 32: /* map_elem: src '=' L_IMM '-'  */
-#line 302 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 300 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 { store(&(yyvsp[-3].lz_value), (yyvsp[-1].i_value), 1); }
-#line 1481 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1470 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 33: /* dst: L_IMM  */
-#line 304 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 302 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        (yyval.i_value) = (yyvsp[0].i_value);
                }
-#line 1489 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1478 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 34: /* dst: R_INVALID  */
-#line 308 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 306 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        (yyval.i_value) = dst_invalid;
                }
-#line 1497 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1486 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 35: /* dst: R_ILSEQ  */
-#line 312 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 310 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        (yyval.i_value) = dst_ilseq;
                }
-#line 1505 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1494 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 36: /* src: %empty  */
-#line 317 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 315 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        set_src(&(yyval.lz_value), src_next, src_next);
                }
-#line 1513 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1502 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 37: /* src: L_IMM  */
-#line 321 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 319 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        set_src(&(yyval.lz_value), (yyvsp[0].i_value), (yyvsp[0].i_value));
                }
-#line 1521 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1510 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 38: /* src: L_IMM '-' L_IMM  */
-#line 325 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 323 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        set_src(&(yyval.lz_value), (yyvsp[-2].i_value), (yyvsp[0].i_value));
                }
-#line 1529 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1518 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
   case 39: /* src: '-' L_IMM  */
-#line 329 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 327 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
                 {
                        set_src(&(yyval.lz_value), src_next, (yyvsp[0].i_value));
                }
-#line 1537 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1526 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
     break;
 
 
-#line 1541 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
+#line 1530 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper_bison.cc"
 
       default: break;
     }
@@ -1619,6 +1608,7 @@ yyerrorlab:
      label yyerrorlab therefore never appears in user code.  */
   if (0)
     YYERROR;
+  ++yynerrs;
 
   /* Do not reclaim the symbols of the rule whose action triggered
      this YYERROR.  */
@@ -1679,7 +1669,7 @@ yyerrlab1:
 `-------------------------------------*/
 yyacceptlab:
   yyresult = 0;
-  goto yyreturn;
+  goto yyreturnlab;
 
 
 /*-----------------------------------.
@@ -1687,24 +1677,22 @@ yyacceptlab:
 `-----------------------------------*/
 yyabortlab:
   yyresult = 1;
-  goto yyreturn;
+  goto yyreturnlab;
 
 
-#if !defined yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
+/*-----------------------------------------------------------.
+| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
+`-----------------------------------------------------------*/
 yyexhaustedlab:
   yyerror (YY_("memory exhausted"));
   yyresult = 2;
-  goto yyreturn;
-#endif
+  goto yyreturnlab;
 
 
-/*-------------------------------------------------------.
-| yyreturn -- parsing is finished, clean up and return.  |
-`-------------------------------------------------------*/
-yyreturn:
+/*----------------------------------------------------------.
+| yyreturnlab -- parsing is finished, clean up and return.  |
+`----------------------------------------------------------*/
+yyreturnlab:
   if (yychar != YYEMPTY)
     {
       /* Make sure we have latest lookahead translation.  See comments at
@@ -1731,7 +1719,7 @@ yyreturn:
   return yyresult;
 }
 
-#line 335 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 333 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
 
 
 static void
@@ -1993,7 +1981,7 @@ set_src_zone(uint32_t val)
                if (rowcol_len <= 32 / rowcol_bits)
                        break;
        /*FALLTHROUGH*/
-       default: 
+       default:
                goto bad;
        }
        rowcol_mask = 1u << (rowcol_bits - 1);
index 05224eae66946a0d175239fe24cf907d4c15c471..7bbfbc376e74e47947a26e0cf0bace59f6f9c12c 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.  */
+/* A Bison parser, made by GNU Bison 3.8.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -77,7 +77,7 @@ extern int yydebug;
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 union YYSTYPE
 {
-#line 237 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
+#line 235 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkcsmapper.y"
 
        uint32_t         i_value;
        char            *s_value;
@@ -94,6 +94,8 @@ typedef union YYSTYPE YYSTYPE;
 
 extern YYSTYPE yylval;
 
+
 int yyparse (void);
 
+
 #endif /* !YY_YY_HOME_MEICHEL_DICOM_DCMTK_FULL_PUBLIC_OFICONV_APPS_MKCSMAPPER_BISON_H_INCLUDED  */
index 333d610b2232cb76d0dbe8849dd4b11352cbea7b..dfb450351ed5dba751d8756db918cad3172bcc15 100644 (file)
@@ -28,9 +28,7 @@
  */
 
 #include "dcmtk/config/osconfig.h"
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
index 51f296269dc777bf7a211b23450404cd7b027bbc..978db3ec3f67fc84b4a6bfaa3cf32a5a3ac32888 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.  */
+/* A Bison parser, made by GNU Bison 3.8.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
    USER NAME SPACE" below.  */
 
 /* Identify Bison output, and Bison version.  */
-#define YYBISON 30705
+#define YYBISON 30802
 
 /* Bison version string.  */
-#define YYBISON_VERSION "3.7.5"
+#define YYBISON_VERSION "3.8.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -98,9 +98,7 @@
  */
 
 #include "dcmtk/config/osconfig.h"
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
@@ -275,7 +273,7 @@ static void  register_named_csid(char *, uint32_t);
 static void     set_invalid(uint32_t);
 static void     set_prop_string(const char *, char **, char **);
 
-#line 279 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 277 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
 
 # ifndef YY_CAST
 #  ifdef __cplusplus
@@ -479,12 +477,18 @@ typedef int yy_state_fast_t;
 # define YY_USE(E) /* empty */
 #endif
 
-#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__
+# if __GNUC__ * 100 + __GNUC_MINOR__ < 407
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")
+# else
+#  define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                           \
     _Pragma ("GCC diagnostic push")                                     \
     _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# endif
 # define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
@@ -699,11 +703,11 @@ static const yytype_int8 yytranslate[] =
 };
 
 #if YYDEBUG
-  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,   220,   220,   223,   224,   225,   226,   227,   228,   229,
-     231,   236,   240,   244,   249
+       0,   218,   218,   221,   222,   223,   224,   225,   226,   227,
+     229,   234,   238,   242,   247
 };
 #endif
 
@@ -732,16 +736,6 @@ yysymbol_name (yysymbol_kind_t yysymbol)
 }
 #endif
 
-#ifdef YYPRINT
-/* YYTOKNUM[NUM] -- (External) token number corresponding to the
-   (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_int16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265
-};
-#endif
-
 #define YYPACT_NINF (-4)
 
 #define yypact_value_is_default(Yyn) \
@@ -752,8 +746,8 @@ static const yytype_int16 yytoknum[] =
 #define yytable_value_is_error(Yyn) \
   0
 
-  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-     STATE-NUM.  */
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
 static const yytype_int8 yypact[] =
 {
       -4,     6,    -3,    -4,    -2,    -1,     0,     1,     3,    -4,
@@ -761,9 +755,9 @@ static const yytype_int8 yypact[] =
       -4,    -4,    -4,    -4,    -4,    -4
 };
 
-  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
-     Performed when YYTABLE does not specify something else to do.  Zero
-     means the default is an error.  */
+/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE does not specify something else to do.  Zero
+   means the default is an error.  */
 static const yytype_int8 yydefact[] =
 {
        3,     0,     2,     1,     0,     0,     0,     0,     0,     4,
@@ -771,21 +765,21 @@ static const yytype_int8 yydefact[] =
        5,     6,     7,     8,     9,    13
 };
 
-  /* YYPGOTO[NTERM-NUM].  */
+/* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
       -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4
 };
 
-  /* YYDEFGOTO[NTERM-NUM].  */
+/* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
        0,     1,     2,    10,    11,    12,    13,    14
 };
 
-  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
-     positive, shift that token.  If negative, reduce the rule whose
-     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule whose
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int8 yytable[] =
 {
        4,     5,     6,     7,     8,     9,     3,     0,    15,    16,
@@ -800,8 +794,8 @@ static const yytype_int8 yycheck[] =
        9
 };
 
-  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-     symbol of state STATE-NUM.  */
+/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
+   state STATE-NUM.  */
 static const yytype_int8 yystos[] =
 {
        0,    12,    13,     0,     3,     4,     5,     6,     7,     8,
@@ -809,14 +803,14 @@ static const yytype_int8 yystos[] =
        8,     8,     8,     8,     8,     9
 };
 
-  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM.  */
 static const yytype_int8 yyr1[] =
 {
        0,    11,    12,    13,    13,    13,    13,    13,    13,    13,
       14,    15,    16,    17,    18
 };
 
-  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM.  */
 static const yytype_int8 yyr2[] =
 {
        0,     2,     1,     0,     2,     3,     3,     3,     3,     3,
@@ -832,6 +826,7 @@ enum { YYENOMEM = -2 };
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
 #define YYERROR         goto yyerrorlab
+#define YYNOMEM         goto yyexhaustedlab
 
 
 #define YYRECOVERING()  (!!yyerrstatus)
@@ -872,10 +867,7 @@ do {                                            \
     YYFPRINTF Args;                             \
 } while (0)
 
-/* This macro is provided for backward compatibility. */
-# ifndef YY_LOCATION_PRINT
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
+
 
 
 # define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
@@ -902,10 +894,6 @@ yy_symbol_value_print (FILE *yyo,
   YY_USE (yyoutput);
   if (!yyvaluep)
     return;
-# ifdef YYPRINT
-  if (yykind < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
-# endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YY_USE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
@@ -1090,6 +1078,7 @@ yyparse (void)
   YYDPRINTF ((stderr, "Starting parse\n"));
 
   yychar = YYEMPTY; /* Cause a token to be read.  */
+
   goto yysetstate;
 
 
@@ -1115,7 +1104,7 @@ yysetstate:
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
-    goto yyexhaustedlab;
+    YYNOMEM;
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
@@ -1143,7 +1132,7 @@ yysetstate:
 # else /* defined YYSTACK_RELOCATE */
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-        goto yyexhaustedlab;
+        YYNOMEM;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
         yystacksize = YYMAXDEPTH;
@@ -1154,7 +1143,7 @@ yysetstate:
           YY_CAST (union yyalloc *,
                    YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
-          goto yyexhaustedlab;
+          YYNOMEM;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
 #  undef YYSTACK_RELOCATE
@@ -1176,6 +1165,7 @@ yysetstate:
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
+
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -1288,54 +1278,54 @@ yyreduce:
   switch (yyn)
     {
   case 2: /* file: property  */
-#line 221 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 219 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 { dump_file(); }
-#line 1294 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1284 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
   case 10: /* name: R_NAME L_STRING  */
-#line 232 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 230 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 {
                        set_prop_string("NAME", &name, &(yyvsp[0].s_value));
                }
-#line 1302 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1292 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
   case 11: /* encoding: R_ENCODING L_STRING  */
-#line 237 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 235 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 {
                        set_prop_string("ENCODING", &encoding, &(yyvsp[0].s_value));
                }
-#line 1310 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1300 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
   case 12: /* variable: R_VARIABLE L_STRING  */
-#line 241 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 239 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 {
                        set_prop_string("VARIABLE", &variable, &(yyvsp[0].s_value));
                }
-#line 1318 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1308 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
   case 13: /* defcsid: R_DEFCSID L_STRING L_IMM  */
-#line 245 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 243 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 {
                        register_named_csid((yyvsp[-1].s_value), (yyvsp[0].i_value));
                        (yyvsp[-1].s_value) = NULL;
                }
-#line 1327 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1317 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
   case 14: /* invalid: R_INVALID L_IMM  */
-#line 250 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 248 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
                 {
                        set_invalid((yyvsp[0].i_value));
                }
-#line 1335 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1325 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
     break;
 
 
-#line 1339 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
+#line 1329 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb_bison.cc"
 
       default: break;
     }
@@ -1417,6 +1407,7 @@ yyerrorlab:
      label yyerrorlab therefore never appears in user code.  */
   if (0)
     YYERROR;
+  ++yynerrs;
 
   /* Do not reclaim the symbols of the rule whose action triggered
      this YYERROR.  */
@@ -1477,7 +1468,7 @@ yyerrlab1:
 `-------------------------------------*/
 yyacceptlab:
   yyresult = 0;
-  goto yyreturn;
+  goto yyreturnlab;
 
 
 /*-----------------------------------.
@@ -1485,24 +1476,22 @@ yyacceptlab:
 `-----------------------------------*/
 yyabortlab:
   yyresult = 1;
-  goto yyreturn;
+  goto yyreturnlab;
 
 
-#if !defined yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
+/*-----------------------------------------------------------.
+| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here.  |
+`-----------------------------------------------------------*/
 yyexhaustedlab:
   yyerror (YY_("memory exhausted"));
   yyresult = 2;
-  goto yyreturn;
-#endif
+  goto yyreturnlab;
 
 
-/*-------------------------------------------------------.
-| yyreturn -- parsing is finished, clean up and return.  |
-`-------------------------------------------------------*/
-yyreturn:
+/*----------------------------------------------------------.
+| yyreturnlab -- parsing is finished, clean up and return.  |
+`----------------------------------------------------------*/
+yyreturnlab:
   if (yychar != YYEMPTY)
     {
       /* Make sure we have latest lookahead translation.  See comments at
@@ -1529,7 +1518,7 @@ yyreturn:
   return yyresult;
 }
 
-#line 253 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 251 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
 
 
 int
index c3b495d74183fb8a2384bdbfd80a7d419870eaad..a29f762c0c1324b571ae066487d0548ec1be9432 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.  */
+/* A Bison parser, made by GNU Bison 3.8.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -70,7 +70,7 @@ extern int yydebug;
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 union YYSTYPE
 {
-#line 208 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
+#line 206 "/home/meichel/dicom/dcmtk-full/public/oficonv/apps/mkesdb.y"
 
        uint32_t        i_value;
        char            *s_value;
@@ -86,6 +86,8 @@ typedef union YYSTYPE YYSTYPE;
 
 extern YYSTYPE yylval;
 
+
 int yyparse (void);
 
+
 #endif /* !YY_YY_HOME_MEICHEL_DICOM_DCMTK_FULL_PUBLIC_OFICONV_APPS_MKESDB_BISON_H_INCLUDED  */
index 7456b4a78328ac063a03052807055e2a35463049..47c7aa4ed75906ec6ec95872a4551ecca304e581 100644 (file)
@@ -34,6 +34,10 @@ if (id != OFreinterpret_cast(iconv_t, -1))
 
     // perform the conversion
     size_t result = OFiconv(id, &src_ptr, &src_len, &dst_ptr, &dst_len);
+
+    // null terminate
+    if (dst_len > 0) *dst_ptr = '\0';
+
     if (result != OFstatic_cast(size_t, -1))
     {
         std::cout << "UTF-8 string: " << output << std::endl;
index 931faa2bf4c47f02ae6d7fac77529fcaec2845f1..14a4842bf6b266b58d70a9e95071d2d715f38b4f 100644 (file)
@@ -32,9 +32,7 @@
 #include "dcmtk/config/osconfig.h"
 #include "dcmtk/oficonv/oidefine.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #include <wchar.h>
 #include <stdint.h>
 
@@ -295,10 +293,11 @@ DCMTK_OFICONV_EXPORT void OFiconvlist(int (*do_one) (unsigned int count, const c
 
 /** resolve the character encoding name specified by the name argument
  *  to its canonical form.
+ *  The resolved name is returned in a newly allocated buffer that must be freed by the caller using free().
  *  @param name encoding name
  *  @return canonical encoding name, NULL if unknown
  */
-DCMTK_OFICONV_EXPORT const char *OFiconv_canonicalize(const char *name);
+DCMTK_OFICONV_EXPORT char *OFiconv_canonicalize(const char *name);
 
 /** This function can retrieve or set specific conversion setting from the
  *  cd conversion descriptor. The request parameter specifies the operation
@@ -310,6 +309,12 @@ DCMTK_OFICONV_EXPORT const char *OFiconv_canonicalize(const char *name);
  */
 DCMTK_OFICONV_EXPORT int OFiconvctl(iconv_t cd, int request, void *argument);
 
+/** This function define a runtime path where to look for the oficonv db files.
+ * This path is used only after the env variable DCMICONVPATH.
+ * @param path to the location of esdb folder
+ */
+DCMTK_OFICONV_EXPORT void OFiconv_setpath(const char *iconv_path);
+
 /// space holder type for OFlocale_charset().
 typedef struct {
     char spaceholder[20];
index d85547d3f911844e40300760c370a5388aebbbfb..66be50c9a957244720e4547ffce413f0e53de051 100644 (file)
@@ -1,5 +1,6 @@
 citrus_bcs.o: citrus_bcs.c ../../config/include/dcmtk/config/osconfig.h \
- citrus_bcs.h
+ ../include/dcmtk/oficonv/iconv.h ../include/dcmtk/oficonv/oidefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h citrus_bcs.h
 citrus_bcs_strtol.o: citrus_bcs_strtol.c \
  ../../config/include/dcmtk/config/osconfig.h citrus_bcs.h \
  citrus_strtol.h
@@ -246,7 +247,7 @@ oficonv_iconv.o: oficonv_iconv.c \
 oficonv_logger.o: oficonv_logger.c \
  ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/oficonv/iconv.h ../include/dcmtk/oficonv/oidefine.h \
- ../../ofstd/include/dcmtk/ofstd/ofexport.h
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h citrus_lock.h
 oficonv_strcasestr.o: oficonv_strcasestr.c \
  ../../config/include/dcmtk/config/osconfig.h oficonv_strcasestr.h
 oficonv_strlcpy.o: oficonv_strlcpy.c \
index d514dcf711dc853af0f65563542ff6af6c6290b9..3010d0e8276b659e1ff483e3c64652a12773b9f3 100644 (file)
  */
 
 #include "dcmtk/config/osconfig.h"
+#include "dcmtk/oficonv/iconv.h"
 #include "citrus_bcs.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
+char *oficonv_path = NULL;
+
+void OFiconv_setpath(const char *runtime_path) {
+    if (oficonv_path) {
+        free(oficonv_path);
+        oficonv_path = NULL;
+    }
+    if (runtime_path) {
+        oficonv_path = strdup(runtime_path);
+    }
+}
+
 /*
  * case insensitive comparison between two C strings.
  */
@@ -184,6 +197,9 @@ void get_data_path(char *path_out, size_t path_size, const char *dirname, const
     // retrieve the DCMICONVPATH environment variable
     env = getenv(OFICONV_PATH_VARIABLE);
 
+    // if the environment variable is not set, use the runtime oficonv path instead:
+    if ( env == NULL && oficonv_path != NULL ) env = oficonv_path;
+
     // if the environment variable is not set, use DEFAULT_SUPPORT_DATA_DIR instead
     if (env == NULL) env = DEFAULT_SUPPORT_DATA_DIR;
 
index 54e347eba3fd1e9193ebfec1708da3d197da1832..ac8d3f06d0177ca9c531a25861bb33f8c514a85d 100644 (file)
@@ -29,9 +29,7 @@
 
 #include "dcmtk/config/osconfig.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_WINDOWS_H
 #include <windows.h>
 #endif
index d53a0371bd9e44a300a2accbc95659365ee3a364..ec5277439a009d392ccb58d16f86e12f7dbb6559 100644 (file)
 #include "dcmtk/oficonv/queue.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index 67cf247bca42f02ae1aa9d6e3f67285d1d6d584c..57294b725793372977ab18d9c6426b7be43d3ce8 100644 (file)
@@ -28,9 +28,7 @@
 #include "citrus_csmapper.h"
 
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
index e8c649c4f65f5cea7dba099923a57f76808e38df..2c4b2b5484ef4dba6032adb0f9f118c3ba5c59b4 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_db.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
index 6f4a23f0c647788115f26aae1e54ec39a0735b18..11e7ea224df76c5d828eed994255cbc513ddee72 100644 (file)
@@ -27,9 +27,7 @@
 #include "dcmtk/config/osconfig.h"
 #include "citrus_db_factory.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
index 92c062028e43045c4ba2505a1a326668e77a4cd6..4d41a9413f760ca68ad87c999caeca87161ff6d9 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_db_hash.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <stdio.h>
 #include <string.h>
 
index 9770b10b53cc1911e87360d287f303bbf5b00c23..bfe53a98b2198858e126d90d6a152cea9db1253b 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_dechanyu.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
 #ifndef __CONCAT
 #define __CONCAT(x,y) x ## y
 #endif
index 5de0eaed020f15cfc3e98d3a15344d3ca547c770..c87b33fcb5b71248cc0c0806bd08024c23b6feb2 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_esdb.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index 53d292803e093bfc3a4cf8758941e3366059eca6..ce0a51cdbcad5df4246088daa8fcec0eeefea1d0 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_euc.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index c2cadfcb105890229f95c821af9a5bc471be63aa..2a1d36d191112ede390034f5312d5bc45d63b1e9 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_euctw.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index 9b7a34f03b688e2cd3966e8b1336348e390bab58..c0c6b2151d04f8de886ae4010fa50327e9848a3d 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_gbk2k.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index 6216f48a5d8f471f9f8efa60f962fafde37d2bb8..3dbcffd4beda9c49ec47af276861545ba305f143 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_hash.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <stdio.h>
 #include <string.h>
 
index 4bf175338a9413470b4d52ba252e7bdc13a23a7b..3c66d6a32c2a6fc680daf5647b9b0add47bda4f2 100644 (file)
@@ -28,9 +28,7 @@
 #include "dcmtk/config/osconfig.h"
 #include "citrus_hz.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
index 193fc75ac18b69166a2f439df409683e5e01ccb5..0b72f792f53b5a7e017b10f6f54fe6b0d8deab2e 100644 (file)
@@ -27,9 +27,7 @@
 #include "dcmtk/config/osconfig.h"
 #include "citrus_iconv.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
 #else
@@ -134,7 +132,7 @@ open_shared(struct _citrus_iconv_shared * * rci,
     int ret;
 
 #ifdef DCMTK_ENABLE_ICONV_PASSTHROUGH
-    /* 
+    /*
      * Use a pass-through when the (src,dest) encodings are the same.
      */
     module = (strcmp(src, dst) != 0) ? "iconv_std" : "iconv_none";
@@ -387,7 +385,7 @@ _citrus_iconv_close_nofree(struct _citrus_iconv *cv)
     }
 }
 
-const char
+char
 *_citrus_iconv_canonicalize(const char *name)
 {
     char *buf;
index 13081e1c3ce747d5bf2dd74c7cf93465532e7250..1a871444bf33102b4c0c05efa44c5ac77a7419b8 100644 (file)
@@ -35,11 +35,10 @@ struct _citrus_iconv_ops;
 struct _citrus_iconv;
 
 BEGIN_EXTERN_C
-int      _citrus_iconv_open(struct _citrus_iconv * * ,
-            const char * , const char * );
-void         _citrus_iconv_close(struct _citrus_iconv *);
-void         _citrus_iconv_close_nofree(struct _citrus_iconv *);
-const char  *_citrus_iconv_canonicalize(const char *);
+int   _citrus_iconv_open(struct _citrus_iconv * * , const char * , const char * );
+void  _citrus_iconv_close(struct _citrus_iconv *);
+void  _citrus_iconv_close_nofree(struct _citrus_iconv *);
+char *_citrus_iconv_canonicalize(const char *);
 END_EXTERN_C
 
 
index 9afdbce63eedff629bfb5aebc11680eeb7bd9809..1e500b12d1b6b4d12b5aa5bfcb6b794e1d1397bb 100644 (file)
@@ -110,14 +110,14 @@ struct _citrus_iconv_shared {
     _citrus_module_t                          ci_module;
     unsigned int                              ci_used_count;
     char                                     *ci_convname;
-    bool                                      ci_discard_ilseq;
-    struct iconv_hooks                       *ci_hooks;
-    bool                                      ci_ilseq_invalid;
 };
 
 struct _citrus_iconv {
     struct _citrus_iconv_shared *cv_shared;
     void                        *cv_closure;
+    struct iconv_hooks          *ci_hooks;
+    bool                         ci_discard_ilseq;
+    bool                         ci_ilseq_invalid;
 };
 
 #endif
index ee1050d4e329914518b152a876e92ba235f71e0c..6974ce5d1373e7ea6e28fd03f8090d2ae2ea8f77 100644 (file)
@@ -120,9 +120,9 @@ _citrus_iconv_none_iconv_convert(struct _citrus_iconv * ci ,
         len = *outbytes;
     }
     memcpy(*out, *in, len);
-    in += len;
+    *in += len;
     *inbytes -= len;
-    out += len;
+    *out += len;
     *outbytes -= len;
     *invalids = 0;
     if (e2big)
index 7b984a54761ed5a5068e70966b89ab3f97d46135..aef71e0af83aae48d43086c269a2a9454c322d4b 100644 (file)
@@ -522,10 +522,10 @@ _citrus_iconv_std_iconv_convert(struct _citrus_iconv * cv,
         tmpin = *in;
         szrin = szrout = 0;
         ret = mbtocsx(&sc->sc_src_encoding, &csid, &idx, &tmpin,
-            *inbytes, &szrin, cv->cv_shared->ci_hooks);
+            *inbytes, &szrin, cv->ci_hooks);
 
         if (ret != 0 && (ret != EILSEQ ||
-            !cv->cv_shared->ci_discard_ilseq)) {
+            !cv->ci_discard_ilseq)) {
                 goto err;
         } else if (ret == EILSEQ) {
                 /*
@@ -565,18 +565,18 @@ _citrus_iconv_std_iconv_convert(struct _citrus_iconv * cv,
                  * Some software depends on this behavior
                  * though this is against POSIX specification.
                  */
-                if (cv->cv_shared->ci_ilseq_invalid != 0) {
+                if (cv->ci_ilseq_invalid != 0) {
                         ret = EILSEQ;
                         goto err;
                 }
                 inval++;
                 szrout = 0;
                 if ((((flags & _CITRUS_ICONV_F_HIDE_INVALID) == 0) &&
-                    !cv->cv_shared->ci_discard_ilseq) &&
+                    !cv->ci_discard_ilseq) &&
                     is->is_use_invalid) {
                     ret = wctombx(&sc->sc_dst_encoding,
                         *out, *outbytes, is->is_invalid,
-                        &szrout, cv->cv_shared->ci_hooks);
+                        &szrout, cv->ci_hooks);
                     if (ret)
                         goto err;
                 }
@@ -587,7 +587,7 @@ _citrus_iconv_std_iconv_convert(struct _citrus_iconv * cv,
         /* csid/index -> mb */
         ret = cstombx(&sc->sc_dst_encoding,
             *out, *outbytes, csid, idx, &szrout,
-            cv->cv_shared->ci_hooks);
+            cv->ci_hooks);
         if (ret)
             goto err;
 next:
index 31e6ca10d407ce2751c49222e12e2592e9470855..5e44de865bdf75a8014170dbbb35e9862b65a89e 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_iso2022.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index cd1b300b24253e6dbc5e9b6a704118c737948677..0bca956ae40c446163a022efbe67fb7858c8ef22 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_euc.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index 653e11af758cfa4c01f305302b06d23ec035bde4..ac40c7529ca497ad765bfbbd088ff0ca99c94abc 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_johab.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index 05fdd01feb0f2664111c4a62c4211449d5e27ec6..30b8d8bf6da88b3147c379b961dd5ed88c24bd43 100644 (file)
 #ifdef HAVE_WINDOWS_H
 
 #include <windows.h>
-#define WLOCK(lock)  AcquireSRWLockExclusive(lock);
-#define UNLOCK(lock) ReleaseSRWLockExclusive(lock);
+#define WLOCK(lock)   AcquireSRWLockExclusive(lock);
+#define UNLOCK(lock)  ReleaseSRWLockExclusive(lock);
+#define RLOCK(lock)   AcquireSRWLockShared(lock);
+#define UNRLOCK(lock) ReleaseSRWLockShared(lock);
 
 #else /* HAVE_WINDOWS_H */
 
 #ifdef HAVE_PTHREAD_H
 
 #include <pthread.h>
-#define WLOCK(lock)  pthread_rwlock_wrlock(lock);
-#define UNLOCK(lock) pthread_rwlock_unlock(lock);
+#define WLOCK(lock)   pthread_rwlock_wrlock(lock);
+#define UNLOCK(lock)  pthread_rwlock_unlock(lock);
+#define RLOCK(lock)   pthread_rwlock_rdlock(lock);
+#define UNRLOCK(lock) pthread_rwlock_unlock(lock);
 
 #else /* HAVE_PTHREAD_H */
 
 
 #else /* WITH_THREADS */
 
-#define WLOCK(lock)  /* nothing */ ;
-#define UNLOCK(lock) /* nothing */ ;
+#define WLOCK(lock)   /* nothing */ ;
+#define UNLOCK(lock)  /* nothing */ ;
+#define RLOCK(lock)   /* nothing */ ;
+#define UNRLOCK(lock) /* nothing */ ;
 
 #endif /* WITH_THREADS */
 
index 51d9516688dc38ecfe361ec791625e811ce47381..4f7fbe610ec9df4e872d6eb956c2b684db8ad934 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_lookup.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
 #endif
index 9c0fa72bd06e2dc9e32ecea92114cdf3092f2759..eb1769a96974d2360da6274b004b93a9f69978db 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_mapper.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
 
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
@@ -197,14 +193,17 @@ lookup_mapper_entry(const char *dir, const char *mapname, void *linebuf,
     /* get module name */
     *module = p;
     cq = _citrus_bcs_skip_nonws_len(cp, &len);
-    strlcpy(p, cp, (size_t)(cq - cp + 1));
+    /* we cannot use strlcpy here because cp is not guaranteed to be null terminated */
+    strncpy(p, cp, (size_t)(cq - cp));
+    *(p + (cq - cp)) = '\0';
     p += cq - cp + 1;
 
     /* get variable */
     *variable = p;
     cp = _citrus_bcs_skip_ws_len(cq, &len);
-    strlcpy(p, cp, len + 1);
-
+    /* we cannot use strlcpy here because cp is not guaranteed to be null terminated */
+    strncpy(p, cp, len);
+    *(p+len) = '\0';
     ret = 0;
 
 quit:
index 0b42f62666d3e165f388d7b602c34eb7783ce920..be245cbf0c02c856a188d6501d0873b01ed99198 100644 (file)
@@ -338,7 +338,8 @@ static void
 /*ARGSUSED*/
 _citrus_mapper_zone_mapper_uninit(struct _citrus_csmapper *cm )
 {
-    (void) cm;
+    if (cm && cm->cm_closure)
+        free(cm->cm_closure);
 }
 
 static int
index 826c5bed5e265a7895a70550990961aa84d8e245..2be75429ba2dcf417cb2ab00bd135da81d838c9a 100644 (file)
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
 
 #include <errno.h>
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>  /* for O_RDONLY, O_CLOEXEC */
-#endif
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
index e8ae9db5cbf6c9376545e88172cbdcf09721ecae..0454d84c99150599f89a652ab8cc5820b17e85b0 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_module.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
 #endif
index 7aedd9ee5952ca8711607d94a0095541d8223772..7349f95139ad8964963581e70f7e52cf24e0807d 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_mskanji.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index 2fdb254bc0e58b753e2eef0009874b24067a4754..ae2f5a0d85841b7422ccdb60486cfa02b8bb4a44 100644 (file)
 
 #include "dcmtk/oficonv/iconv.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
index 4254690ee9beebae7091424098f788311329a3b5..1e5a51193ae364b2f9978174eb301995a10f5d79 100644 (file)
 #include <stdint.h>
 #include <string.h>
 #include <stdbool.h>
-
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 
 
 struct _citrus_region {
index afcc0888188dfacde121fa0f83b9b59deed20816..3ad1461a4a7660fb3f7c429c13ba9d6ecff11e7d 100644 (file)
@@ -29,9 +29,7 @@
 
 #include "dcmtk/config/osconfig.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #include <stdint.h>
 
 #ifndef OFICONV_CITRUS_WC_T_DEFINED
index cb53ff79e04b617427443dd02a87cf41e92e6f2d..c1214ea56627225ca362819c90fd478eac199edc 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_utf1632.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index 09abce6afe5f901568fa17b73e43736bb05ba4f8..c7be99b02532d6142865eedf571aaf31e1019568 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_utf8.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
index e3c5b20a1b348559f64522228ec68a62d577a28c..9b1939ff6dc78e6ae55e71bf75809a244e6ed0f9 100644 (file)
         (var) = (tvar))
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index c8141d871a0354654d2fb47c38d7dda837e719b7..771c677421de53cba29fa5ba61af5801c5ea4154 100644 (file)
 #include "dcmtk/config/osconfig.h"
 #include "citrus_zw.h"
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
-
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
index c7a625eaaa31d22bd40b8d7909deb4c438698a50..a20cfe9b6e9b31aee9baa9f18a5995634444e133 100644 (file)
 #include "dcmtk/oficonv/queue.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
-
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
@@ -113,9 +110,9 @@ _iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
         return ((iconv_t)-1);
     }
 
-    handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE");
-    handle->cv_shared->ci_ilseq_invalid = false;
-    handle->cv_shared->ci_hooks = NULL;
+    handle->ci_discard_ilseq = strcasestr(out, "//IGNORE");
+    handle->ci_ilseq_invalid = false;
+    handle->ci_hooks = NULL;
 
     return ((iconv_t)(void *)handle);
 }
@@ -302,10 +299,8 @@ out:
         OF__iconv_free_list(list, sz);
 }
 
-const char
-*OFiconv_canonicalize(const char *name)
+char *OFiconv_canonicalize(const char *name)
 {
-
     return (_citrus_iconv_canonicalize(name));
 }
 
@@ -342,22 +337,22 @@ OFiconvctl(iconv_t cd, int request, void *argument)
     case ICONV_SET_TRANSLITERATE:
         return  ((*i == 1) ? 0 : -1);
     case ICONV_GET_DISCARD_ILSEQ:
-        *i = cv->cv_shared->ci_discard_ilseq ? 1 : 0;
+        *i = cv->ci_discard_ilseq ? 1 : 0;
         return (0);
     case ICONV_SET_DISCARD_ILSEQ:
-        cv->cv_shared->ci_discard_ilseq = *i;
+        cv->ci_discard_ilseq = *i;
         return (0);
     case ICONV_SET_HOOKS:
-        cv->cv_shared->ci_hooks = hooks;
+        cv->ci_hooks = hooks;
         return (0);
     case ICONV_SET_FALLBACKS:
         errno = EOPNOTSUPP;
         return (-1);
     case ICONV_GET_ILSEQ_INVALID:
-        *i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0;
+        *i = cv->ci_ilseq_invalid ? 1 : 0;
         return (0);
     case ICONV_SET_ILSEQ_INVALID:
-        cv->cv_shared->ci_ilseq_invalid = *i;
+        cv->ci_ilseq_invalid = *i;
         return (0);
     default:
         errno = EINVAL;
@@ -383,4 +378,5 @@ const char *OFlocale_charset(iconv_locale_allocation_t *buf)
 void OFiconv_cleanup()
 {
   _citrus_csmapper_free();
+  OFiconv_setpath(NULL);
 }
index 839e6870a6501fb47aa3a8e33b3b0e7d24235c07..f29385bf4d7352bd952736ea7e2fee5da10fa9a1 100644 (file)
 
 #include "dcmtk/config/osconfig.h"
 #include "dcmtk/oficonv/iconv.h"
+#include "citrus_lock.h"
 #include <stdio.h>
 
+#ifdef WITH_THREADS
+#ifdef HAVE_WINDOWS_H
+static SRWLOCK logger_lock = SRWLOCK_INIT;
+#elif defined(HAVE_PTHREAD_H)
+static pthread_rwlock_t logger_lock = PTHREAD_RWLOCK_INITIALIZER;
+#endif
+#endif
+
 static oficonv_logger_callback_t logger_callback = NULL;
 static int log_level = 3;
 
 void set_oficonv_logger_callback(oficonv_logger_callback_t callback)
 {
+  WLOCK(&logger_lock);
   logger_callback = callback;
+  UNLOCK(&logger_lock);
 }
 
 oficonv_logger_callback_t get_oficonv_logger_callback()
 {
-  return logger_callback;
+  RLOCK(&logger_lock);
+  oficonv_logger_callback_t result = logger_callback;
+  UNRLOCK(&logger_lock);
+  return result;
 }
 
 void set_oficonv_log_level(int level)
@@ -43,6 +57,7 @@ void set_oficonv_log_level(int level)
 
 void oficonv_log(int level, const char *text1, const char *text2, const char *text3)
 {
+  RLOCK(&logger_lock);
   if (logger_callback) logger_callback(level, text1, text2, text3);
   else
   {
@@ -70,4 +85,5 @@ void oficonv_log(int level, const char *text1, const char *text2, const char *te
     }
     if (level >= log_level) fprintf(stderr, "%s %s%s%s\n", level_text, text1, text2, text3);
   }
+  UNRLOCK(&logger_lock);
 }
index 968149c8afa7145234edddd5b1a48d43f6b661a9..81c38ce5069e90d71bb0b96f5870419e772b2e8a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2022, OFFIS e.V.
+ *  Copyright (C) 2022-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -109,4 +109,7 @@ OFTEST_REGISTER(oficonv__iconv);
 OFTEST_REGISTER(oflocale_charset);
 OFTEST_REGISTER(oficonvctl);
 
+// finally clean up memory
+OFTEST_REGISTER(oficonv_cleanup);
+
 OFTEST_MAIN("oficonv")
index ad12fd02487047c52a9af8c95d60b59b1843b50b..6a46eab25f1558ceed2200c29efbfcb346385f81 100644 (file)
@@ -187,7 +187,7 @@ OFTEST(oficonv_open)
 
 OFTEST(oficonv_canonicalize)
 {
-  const char *c;
+  char *c;
 
   // these are the canonical names we expect as result
   OFString latin1("ISO-8859-1");
@@ -213,46 +213,46 @@ OFTEST(oficonv_canonicalize)
 
   // exercise all synonyms for ISO-8859-1 as defined in oficonv/datasrc/esdb/esdb.alias,
   // with mixed uppercase/lowercase spellings
-  c = OFiconv_canonicalize("cp819");            OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("csisolatin1");      OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("ibm819");           OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("iso_8859-1");       OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("iso_8859-1:1987");  OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("iso-ir-100");       OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("iso8859-1");        OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("l1");               OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("latin1");           OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("CP819");            OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("CSISOLATIN1");      OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("IBM819");           OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("ISO_8859-1");       OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("ISO_8859-1:1987");  OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("ISO-IR-100");       OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("ISO8859-1");        OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("L1");               OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("LATIN1");           OFCHECK(c && latin1 == c);
-  c = OFiconv_canonicalize("cSiSoLaTiN1");      OFCHECK(c && latin1 == c);
+  c = OFiconv_canonicalize("cp819");            OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("csisolatin1");      OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("ibm819");           OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("iso_8859-1");       OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("iso_8859-1:1987");  OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("iso-ir-100");       OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("iso8859-1");        OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("l1");               OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("latin1");           OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("CP819");            OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("CSISOLATIN1");      OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("IBM819");           OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("ISO_8859-1");       OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("ISO_8859-1:1987");  OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("ISO-IR-100");       OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("ISO8859-1");        OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("L1");               OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("LATIN1");           OFCHECK(c && latin1 == c);  if (c) free(c);
+  c = OFiconv_canonicalize("cSiSoLaTiN1");      OFCHECK(c && latin1 == c);  if (c) free(c);
 
   // exercise at least one synonym for each supported character set
-  c = OFiconv_canonicalize("gb2312");           OFCHECK(c && euc_cn == c);
-  c = OFiconv_canonicalize("iso-ir-149");       OFCHECK(c && euc_kr == c);
-  c = OFiconv_canonicalize("iso-ir-101");       OFCHECK(c && latin2 == c);
-  c = OFiconv_canonicalize("latin3");           OFCHECK(c && latin3 == c);
-  c = OFiconv_canonicalize("iso_8859-4");       OFCHECK(c && latin4 == c);
-  c = OFiconv_canonicalize("cyrillic");         OFCHECK(c && cyrillic == c);
-  c = OFiconv_canonicalize("arabic");           OFCHECK(c && arabic == c);
-  c = OFiconv_canonicalize("greek");            OFCHECK(c && greek == c);
-  c = OFiconv_canonicalize("hebrew");           OFCHECK(c && hebrew == c);
-  c = OFiconv_canonicalize("iso-ir-148");       OFCHECK(c && latin5 == c);
-  c = OFiconv_canonicalize("tis-620");          OFCHECK(c && thai == c);
-  c = OFiconv_canonicalize("iso-ir-203");       OFCHECK(c && latin9 == c);
-  c = OFiconv_canonicalize("ascii");            OFCHECK(c && ascii == c);
-  c = OFiconv_canonicalize("jis_x0201");        OFCHECK(c && jisx0201 == c);
-  c = OFiconv_canonicalize("jis0208");          OFCHECK(c && jisx0208 == c);
-  c = OFiconv_canonicalize("ms_kanji");         OFCHECK(c && shift_jis == c);
-  c = OFiconv_canonicalize("jis_x0212");        OFCHECK(c && jisx0212 == c);
-  c = OFiconv_canonicalize("utf8");             OFCHECK(c && utf8 == c);
-  c = OFiconv_canonicalize("unicode");          OFCHECK(c && utf16 == c);
+  c = OFiconv_canonicalize("gb2312");           OFCHECK(c && euc_cn == c);     if (c) free(c);
+  c = OFiconv_canonicalize("iso-ir-149");       OFCHECK(c && euc_kr == c);     if (c) free(c);
+  c = OFiconv_canonicalize("iso-ir-101");       OFCHECK(c && latin2 == c);     if (c) free(c);
+  c = OFiconv_canonicalize("latin3");           OFCHECK(c && latin3 == c);     if (c) free(c);
+  c = OFiconv_canonicalize("iso_8859-4");       OFCHECK(c && latin4 == c);     if (c) free(c);
+  c = OFiconv_canonicalize("cyrillic");         OFCHECK(c && cyrillic == c);   if (c) free(c);
+  c = OFiconv_canonicalize("arabic");           OFCHECK(c && arabic == c);     if (c) free(c);
+  c = OFiconv_canonicalize("greek");            OFCHECK(c && greek == c);      if (c) free(c);
+  c = OFiconv_canonicalize("hebrew");           OFCHECK(c && hebrew == c);     if (c) free(c);
+  c = OFiconv_canonicalize("iso-ir-148");       OFCHECK(c && latin5 == c);     if (c) free(c);
+  c = OFiconv_canonicalize("tis-620");          OFCHECK(c && thai == c);       if (c) free(c);
+  c = OFiconv_canonicalize("iso-ir-203");       OFCHECK(c && latin9 == c);     if (c) free(c);
+  c = OFiconv_canonicalize("ascii");            OFCHECK(c && ascii == c);      if (c) free(c);
+  c = OFiconv_canonicalize("jis_x0201");        OFCHECK(c && jisx0201 == c);   if (c) free(c);
+  c = OFiconv_canonicalize("jis0208");          OFCHECK(c && jisx0208 == c);   if (c) free(c);
+  c = OFiconv_canonicalize("ms_kanji");         OFCHECK(c && shift_jis == c);  if (c) free(c);
+  c = OFiconv_canonicalize("jis_x0212");        OFCHECK(c && jisx0212 == c);   if (c) free(c);
+  c = OFiconv_canonicalize("utf8");             OFCHECK(c && utf8 == c);       if (c) free(c);
+  c = OFiconv_canonicalize("unicode");          OFCHECK(c && utf16 == c);      if (c) free(c);
 }
 
 
@@ -648,3 +648,8 @@ OFTEST(oficonvctl)
     OFiconv_close(id3);
   }
 }
+
+OFTEST(oficonv_cleanup)
+{
+    OFiconv_cleanup();
+}
index 38878d70fe212d4d70b7c6367446ff1b818fdfa7..2e46bb597a2d3b11a2195df79dc282b1c9ae79b3 100644 (file)
 #endif
 
 #if defined (DCMTK_OFLOG_UNICODE)
-#  if defined (_MSC_VER) && _MSC_VER >= 1400
+#  if defined (_MSC_VER)
 #    define DCMTK_LOG4CPLUS_FSTREAM_ACCEPTS_WCHAR_T
-#  endif
-#  if defined (_MSC_VER) && _MSC_VER >= 1600
 #    define DCMTK_LOG4CPLUS_HAVE_CODECVT_UTF8_FACET
 #    define DCMTK_LOG4CPLUS_HAVE_CODECVT_UTF16_FACET
 #  endif
 #  define __has_feature(X) 0
 #endif
 
-#if (defined (_MSC_VER) && _MSC_VER >= 1600) \
-    || defined (__GXX_EXPERIMENTAL_CXX0X__)
+#if defined (_MSC_VER) || defined (__GXX_EXPERIMENTAL_CXX0X__)
 #  define DCMTK_LOG4CPLUS_HAVE_modern_cxx_support
 #endif
 
index 6f4a46e81ffe938a8c26060220d0e8e83c2ee74e..5878555aef1218fc6f8a2378240f3351166a0065 100644 (file)
 #endif
 
 /* */
-#ifdef HAVE_SYS_TYPES_H
 #define DCMTK_LOG4CPLUS_HAVE_SYS_TYPES_H
-#endif
 
 /* */
-#ifdef HAVE_SYS_STAT_H
 #define DCMTK_LOG4CPLUS_HAVE_SYS_STAT_H
-#endif
 
 /* */
 #ifdef HAVE_SYS_SYSCALL_H
@@ -70,9 +66,7 @@
 #endif
 
 /* */
-#ifdef HAVE_FCNTL_H
 #define DCMTK_LOG4CPLUS_HAVE_FCNTL_H
-#endif
 
 /* */
 #define DCMTK_LOG4CPLUS_HAVE_STDARG_H
 #endif
 
 /* */
-#ifdef HAVE_GETPID
 #define DCMTK_LOG4CPLUS_HAVE_GETPID
-#endif
 
 /* */
 #ifdef HAVE_PROTOTYPE_GETTIMEOFDAY
 #endif
 
 /* */
-#ifdef HAVE_STAT
 #define DCMTK_LOG4CPLUS_HAVE_STAT
-#endif
 
 /* */
 #ifdef WITH_THREADS
 #endif
 
 /* */
-#ifdef HAVE_VSNPRINTF
 #define DCMTK_LOG4CPLUS_HAVE_VSNPRINTF
-#endif
 
 /* */
 #ifdef HAVE_PROTOTYPE_STD__VSNPRINTF
index eb8d6e1d3cf984f396960772cffbe948914eb9e6..b8e5e0e661e0b0a39fb16b4994680118b693582d 100644 (file)
@@ -30,8 +30,7 @@
 
 #ifdef _WIN32
 
-/* This used to be _MSC_VER >= 1400, but MSVC 2005 is broken */
-#if (defined (_MSC_VER) && _MSC_VER > 1400)
+#ifdef _MSC_VER
 #  define DCMTK_LOG4CPLUS_HAVE_INTRIN_H
 #endif
 
@@ -39,7 +38,7 @@
 #define DCMTK_LOG4CPLUS_HAVE_TIME_H
 #define DCMTK_LOG4CPLUS_HAVE_SYS_TIMEB_H
 #define DCMTK_LOG4CPLUS_HAVE_FTIME
-#if defined (_MSC_VER) || defined (__BORLANDC__)
+#if defined (_MSC_VER) || defined (HAVE_CLASSIC_BORLAND_COMPILER)
 #define DCMTK_LOG4CPLUS_HAVE_GMTIME_S
 #endif
 
@@ -68,9 +67,6 @@
 // MSVC has both and so does MinGW.
 #define DCMTK_LOG4CPLUS_HAVE_VSNPRINTF
 #define DCMTK_LOG4CPLUS_HAVE__VSNPRINTF
-#if _MSC_VER <= 1200 /* Additional settings for VC6 and older */
-#undef DCMTK_LOG4CPLUS_HAVE_VSNPRINTF
-#endif
 
 // MS secure versions of vprintf().
 #ifdef HAVE_VSPRINTF_S
 #  pragma warning( disable : 4251 )
 
 #  define DCMTK_LOG4CPLUS_INLINES_ARE_EXPORTED
-
-#  if _MSC_VER >= 1400
-#    define DCMTK_LOG4CPLUS_WORKING_LOCALE
-#    define DCMTK_LOG4CPLUS_HAVE_FUNCTION_MACRO
-#    define DCMTK_LOG4CPLUS_HAVE_FUNCSIG_MACRO
-#    define DCMTK_LOG4CPLUS_HAVE_C99_VARIADIC_MACROS
-#  endif
+#  define DCMTK_LOG4CPLUS_WORKING_LOCALE
+#  define DCMTK_LOG4CPLUS_HAVE_FUNCTION_MACRO
+#  define DCMTK_LOG4CPLUS_HAVE_FUNCSIG_MACRO
+#  define DCMTK_LOG4CPLUS_HAVE_C99_VARIADIC_MACROS
 #endif
 
 #if defined (__GNUC__)
index 7c5a2ee755efc7c5c657bc80ab577c5c21baf33e..41636c19532728d14a3f02fb300a57714af726b9 100644 (file)
@@ -35,7 +35,7 @@
 #include <cstdio>
 #include <stdexcept>
 
-#if defined (__BORLANDC__)
+#if defined (HAVE_CLASSIC_BORLAND_COMPILER)
 // For _wrename() and _wremove() on Windows.
 #  include <stdio.h>
 #endif
@@ -73,7 +73,7 @@ namespace
 long const DCMTK_LOG4CPLUS_FILE_NOT_FOUND = ENOENT;
 
 
-static 
+static
 long
 file_rename (tstring const & src, tstring const & target)
 {
@@ -122,8 +122,8 @@ loglog_renaming_result (helpers::LogLog & loglog, tstring const & src,
     if (ret == 0)
     {
         loglog.debug (
-            DCMTK_LOG4CPLUS_TEXT("Renamed file ") 
-            + src 
+            DCMTK_LOG4CPLUS_TEXT("Renamed file ")
+            + src
             + DCMTK_LOG4CPLUS_TEXT(" to ")
             + target);
     }
@@ -149,7 +149,7 @@ loglog_opening_result (helpers::LogLog & loglog,
     if (! os)
     {
         loglog.error (
-            DCMTK_LOG4CPLUS_TEXT("Failed to open file ") 
+            DCMTK_LOG4CPLUS_TEXT("Failed to open file ")
             + filename);
     }
 }
@@ -224,7 +224,7 @@ get_locale_by_name (tstring const & locale_name)
 // FileAppender ctors and dtor
 ///////////////////////////////////////////////////////////////////////////////
 
-FileAppender::FileAppender(const tstring& filename_, 
+FileAppender::FileAppender(const tstring& filename_,
     STD_NAMESPACE ios_base::openmode mode_, bool immediateFlush_)
     : immediateFlush(immediateFlush_)
     , reopenDelay(1)
@@ -239,7 +239,7 @@ FileAppender::FileAppender(const tstring& filename_,
 }
 
 
-FileAppender::FileAppender(const Properties& props, 
+FileAppender::FileAppender(const Properties& props,
                            STD_NAMESPACE ios_base::openmode mode_)
     : Appender(props)
     , immediateFlush(true)
@@ -280,7 +280,7 @@ FileAppender::FileAppender(const Properties& props,
 
 
 void
-FileAppender::init(const tstring& filename_, 
+FileAppender::init(const tstring& filename_,
                    STD_NAMESPACE ios_base::openmode mode_,
                    const log4cplus::tstring& lockFileName_)
 {
@@ -313,7 +313,7 @@ FileAppender::init(const tstring& filename_,
     imbue (get_locale_by_name (localeName));
 
     if(!out.good()) {
-        getErrorHandler()->error(  DCMTK_LOG4CPLUS_TEXT("Unable to open file: ") 
+        getErrorHandler()->error(  DCMTK_LOG4CPLUS_TEXT("Unable to open file: ")
                                  + filename);
         return;
     }
@@ -333,7 +333,7 @@ FileAppender::~FileAppender()
 // FileAppender public methods
 ///////////////////////////////////////////////////////////////////////////////
 
-void 
+void
 FileAppender::close()
 {
     thread::MutexGuard guard (access_mutex);
@@ -370,11 +370,11 @@ FileAppender::append(const spi::InternalLoggingEvent& event)
 {
     if(!out.good()) {
         if(!reopen()) {
-            getErrorHandler()->error(  DCMTK_LOG4CPLUS_TEXT("file is not open: ") 
+            getErrorHandler()->error(  DCMTK_LOG4CPLUS_TEXT("file is not open: ")
                                      + filename);
             return;
         }
-        // Resets the error handler to make it 
+        // Resets the error handler to make it
         // ready to handle a future append error.
         else
             getErrorHandler()->reset();
@@ -522,7 +522,7 @@ RollingFileAppender::rollover(bool alreadyLocked)
     out.close();
     // Reset flags since the C++ standard specified that all the flags
     // should remain unchanged on a close.
-    out.clear(); 
+    out.clear();
 
     if (useLockFile)
     {
@@ -573,8 +573,8 @@ RollingFileAppender::rollover(bool alreadyLocked)
 #endif
 
         loglog.debug (
-            DCMTK_LOG4CPLUS_TEXT("Renaming file ") 
-            + filename 
+            DCMTK_LOG4CPLUS_TEXT("Renaming file ")
+            + filename
             + DCMTK_LOG4CPLUS_TEXT(" to ")
             + target);
         ret = file_rename (filename, target);
@@ -640,7 +640,7 @@ DailyRollingFileAppender::DailyRollingFileAppender(
             + properties.getProperty(DCMTK_LOG4CPLUS_TEXT("Schedule")));
         theSchedule = DAILY;
     }
-    
+
     properties.getInt (maxBackupIndex, DCMTK_LOG4CPLUS_TEXT("MaxBackupIndex"));
 
     init(theSchedule);
@@ -794,12 +794,12 @@ DailyRollingFileAppender::rollover(bool alreadyLocked)
     // possible to rename over existing file, e.g. "log.2009-11-07".
     ret = file_remove (scheduledFilename);
 #endif
-   
+
     // Rename filename to scheduledFilename,
     // e.g. rename "log" to "log.2009-11-07".
     loglog.debug(
         DCMTK_LOG4CPLUS_TEXT("Renaming file ")
-        + filename 
+        + filename
         + DCMTK_LOG4CPLUS_TEXT(" to ")
         + scheduledFilename);
     ret = file_rename (filename, scheduledFilename);
@@ -825,7 +825,7 @@ DailyRollingFileAppender::calculateNextRolloverTime(const Time& t) const
 {
     switch(schedule)
     {
-    case MONTHLY: 
+    case MONTHLY:
     {
         struct tm nextMonthTime;
         t.localtime(&nextMonthTime);
index c79831ea31a49c53d2094ecaed93803bc1956817..a1c0b44269f6d6438acfc078ba3495c6e516946e 100644 (file)
@@ -50,8 +50,6 @@ is_control (tchar ch)
 {
 #if defined (DCMTK_OFLOG_UNICODE)
     return !! STD_NAMESPACE iswcntrl (STD_NAMESPACE char_traits<tchar>::to_int_type (ch));
-#elif defined (_MSC_VER) && _MSC_VER <= 1200 /* MSC6 and older */
-    return !! iscntrl (STD_NAMESPACE char_traits<tchar>::to_int_type (ch));
 #else
     return !! STD_NAMESPACE iscntrl (STD_NAMESPACE char_traits<tchar>::to_int_type (ch));
 #endif
index 3cb0971665db8b58d04843e2d476819a3e65bfc1..ce56b548062096f40c51ece27bf816bb5f7f1726 100644 (file)
@@ -90,9 +90,7 @@ yield()
 #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS)
     sched_yield();
 #elif defined(_WIN32)
-#if !defined(_MSC_VER) || _MSC_VER > 1200 /* MSC 6 doesn't know this */
     if (! SwitchToThread ())
-#endif
         Sleep (0);
 #endif
 }
index 993f298e82eee168ba0ebe3260d3a4b249829034..99bf00ecaeaac40db811423187b1e25fd2f270ba 100644 (file)
@@ -178,10 +178,10 @@ void
 Time::gmtime(tm* t) const
 {
     time_t clock = tv_sec;
-#if defined (DCMTK_LOG4CPLUS_HAVE_GMTIME_S) && defined (_MSC_VER) && _MSC_VER > 1200
-    gmtime_s (t, &clock);
-#elif defined (DCMTK_LOG4CPLUS_HAVE_GMTIME_S) && defined (__BORLANDC__)
+#if defined (DCMTK_LOG4CPLUS_HAVE_GMTIME_S) && defined (HAVE_CLASSIC_BORLAND_COMPILER)
     gmtime_s (&clock, t);
+#elif defined (DCMTK_LOG4CPLUS_HAVE_GMTIME_S) && defined (_MSC_VER)
+    gmtime_s (t, &clock);
 #elif defined (DCMTK_LOG4CPLUS_NEED_GMTIME_R)
     gmtime_r (&clock, t);
 #else
diff --git a/ofstd/include/dcmtk/ofstd/diag/clangprg.def b/ofstd/include/dcmtk/ofstd/diag/clangprg.def
new file mode 100644 (file)
index 0000000..5f49a4a
--- /dev/null
@@ -0,0 +1,7 @@
+/* MacOS 15.5 defines some Clang specific pragmas in header files
+ * without checking if the current compiler is actually Clang.
+ * This code allows us to suppress warnings when compiling with GCC
+ */
+#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#endif
diff --git a/ofstd/include/dcmtk/ofstd/diag/vsconstexp.def b/ofstd/include/dcmtk/ofstd/diag/vsconstexp.def
new file mode 100644 (file)
index 0000000..5a48c30
--- /dev/null
@@ -0,0 +1,7 @@
+// Visual Studio warns if a certain expression is constant
+// i.e. known at compile time and used in a conditional statement.
+// In C++17 constexpr should be used then but we don't want a warning
+// about it.
+#ifdef _MSC_VER
+#pragma warning(disable: 4127)
+#endif
\ No newline at end of file
index 80fa13a3447981f1f2cd412073c158757205a32a..0babe110c4029f2b2b3d61453b22c8d6d3b7c41f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2018, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -267,7 +267,7 @@ public:
      *  @remark This list of code pages is only available if DCMTK is compiled
      *  on Windows Operating Systems (defining _WIN32)
      */
-    //@{
+    ///@{
 
     /// system default Windows ANSI code page.  See Windows function GetACP().
     /// @remark Only available on Windows Operating Systems (defining _WIN32).
@@ -285,7 +285,7 @@ public:
     /// @remark Only available on Windows Operating Systems (defining _WIN32).
     static const unsigned int CPC_UTF8;
 
-    //@}
+    ///@}
 
     // --- static Windows-specific functions ---
 
index 0b99f7b1e0ac4d6b50fa02bd7ea2ade751ab2553..30b5c00712776053ee23e4c49e17bbf9eed3cd89 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2021, OFFIS e.V.
+ *  Copyright (C) 1998-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -35,8 +35,8 @@
  *  macro definition  *
  *--------------------*/
 
-// Only use wchar_t on windows (not mingw) and don't use it on MSC6
-#if defined(HAVE_WINDOWS_H) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER > 1200)
+// Only use wchar_t on windows (not mingw)
+#if defined(HAVE_WINDOWS_H) && !defined(__MINGW32__)
 # define DCMTK_USE_WCHAR_T
 #endif
 #if defined(WIDE_CHAR_MAIN_FUNCTION) && defined(DCMTK_USE_WCHAR_T)
index 63f72bc13d9e9e964590a65c0e09913d8179e632..0f9e39a4cae28ebc57477a3a99622717f160e044 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2023, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -101,7 +101,8 @@ struct DCMTK_OFSTD_EXPORT OFConditionConst
  *  All constants defined here use module number 0, which is reserved for
  *  global definitions. Other constants are defined in other modules.
  */
-//@{
+///@{
+
 /// condition constant: successful completion
 extern DCMTK_OFSTD_EXPORT const OFConditionConst EC_Normal;
 /// condition constant: error, function called with illegal parameters
@@ -155,7 +156,7 @@ extern DCMTK_OFSTD_EXPORT const OFConditionConst EC_IPCMessageQueueEmpty;
 /// condition constant: error, IPC message empty (zero length)
 extern DCMTK_OFSTD_EXPORT const OFConditionConst EC_IPCEmptyMessage;
 
-//@}
+///@}
 
 
 /** use this macro for creating static OFCondition instances. Instead of an
index 87089a67852330b0baf0e09effa2a557aa4b19cc..1f6ad1319ce2435f9c81765be4c79292afd03c8e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2017, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,9 +26,7 @@
 #include "dcmtk/config/osconfig.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>    /* for struct time_t */
-#endif
+#include <sys/types.h>    /* for struct time_t */
 END_EXTERN_C
 
 #include "dcmtk/ofstd/ofstring.h"      /* for class OFString */
index 0590a3857fde3840dc372e27597c47fe57b51590..9fd9e6755568a0058dbb49166942f48f90dbc96f 100644 (file)
 #define DCMTK_DIAGNOSTIC_IGNORE_USE_AFTER_FREE "dcmtk/ofstd/diag/useafree.def"
 #define DCMTK_DIAGNOSTIC_IGNORE_ARRAY_BOUNDS "dcmtk/ofstd/diag/arrybnds.def"
 #define DCMTK_DIAGNOSTIC_IGNORE_UNSIGNED_UNARY_MINUS "dcmtk/ofstd/diag/unarymin.def"
+#define DCMTK_DIAGNOSTIC_IGNORE_CLANG_PRAGMAS_ON_GCC "dcmtk/ofstd/diag/clangprg.def"
+#define DCMTK_DIAGNOSTIC_IGNORE_VISUAL_STUDIO_CONSTANT_EXPRESSION_WARNING "dcmtk/ofstd/diag/vsconstexp.def"
 
 // readable shorthands for compiler version checks
 #define DCMTK_DIAGNOSTIC_MIN_GCC_VERSION(MAJOR, MINOR, PATCH)\
index f64ad5484907a020e27673b6652aa927d970d5ff..4ddb768f412f1455680f8f10a2d24474c4d1c3c0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2006-2024, OFFIS e.V.
+ *  Copyright (C) 2006-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -33,9 +33,7 @@
 #include <cerrno>
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>       /* needed for struct _stati64 on Win32 */
-#endif
 END_EXTERN_C
 
 #ifdef HAVE_UNIX_H
@@ -74,24 +72,17 @@ typedef fpos_t offile_fpos_t;
 // Use POSIX 64 bit file offset type when available
 #ifdef HAVE_OFF64_T
 typedef off64_t offile_off_t;
-#elif !defined(OF_NO_SINT64) // Otherwise use a 64 bit integer
+#else
+// Otherwise use a 64 bit integer
 typedef Sint64 offile_off_t;
-#else // Cry when 64 LFS is required but no 64 bit integer exists
-#error \
-  Could not find a suitable offset-type for LFS64 support.
 #endif
 
 #else // Implicit LFS or no LFS
 
 #if defined(DCMTK_ENABLE_LFS) && DCMTK_ENABLE_LFS == DCMTK_LFS
 #if defined(SIZEOF_FPOS_T) && (!defined(SIZEOF_OFF_T) || SIZEOF_FPOS_T > SIZEOF_OFF_T)
-// strange Windows LFS where sizeof(fpos_t) == 8 but sizeof(off_t) == 4
-#ifndef OF_NO_SINT64 // Use a 64 bit integer
+// strange Windows LFS where sizeof(fpos_t) == 8 but sizeof(off_t) == 4. Use a 64 bit integer
 typedef Sint64 offile_off_t;
-#else // Cry when LFS is required but no 64 bit integer exists
-#error \
-  Could not find a suitable offset-type for LFS support.
-#endif
 #else
 typedef off_t offile_off_t;
 #endif
diff --git a/ofstd/include/dcmtk/ofstd/ofjsmn.h b/ofstd/include/dcmtk/ofstd/ofjsmn.h
new file mode 100644 (file)
index 0000000..392a483
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef OFJSMN_H
+#define OFJSMN_H
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/oftypes.h"
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef JSMN_STATIC
+#define JSMN_API static
+#else
+#define JSMN_API extern DCMTK_OFSTD_EXPORT
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ *     o Object
+ *     o Array
+ *     o String
+ *     o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+  JSMN_UNDEFINED = 0,
+  JSMN_OBJECT = 1 << 0,
+  JSMN_ARRAY = 1 << 1,
+  JSMN_STRING = 1 << 2,
+  JSMN_PRIMITIVE = 1 << 3
+} jsmntype_t;
+
+enum jsmnerr {
+  /* Not enough tokens were provided */
+  JSMN_ERROR_NOMEM = -1,
+  /* Invalid character inside JSON string */
+  JSMN_ERROR_INVAL = -2,
+  /* The string is not a full JSON packet, more bytes expected */
+  JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * type                type (object, array, string etc.)
+ * start       start position in JSON data string
+ * end         end position in JSON data string
+ */
+typedef struct jsmntok {
+  jsmntype_t type;
+  int start;
+  int end;
+  int size;
+#ifdef JSMN_PARENT_LINKS
+  int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string.
+ */
+typedef struct jsmn_parser {
+  unsigned int pos;     /* offset in the JSON string */
+  unsigned int toknext; /* next token to allocate */
+  int toksuper;         /* superior token node, e.g. parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each
+ * describing
+ * a single JSON object.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                        jsmntok_t *tokens, const unsigned int num_tokens);
+
+#ifndef JSMN_HEADER
+/**
+ * Allocates a fresh unused token from the token pool.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+                                   const size_t num_tokens) {
+  jsmntok_t *tok;
+  if (parser->toknext >= num_tokens) {
+    return NULL;
+  }
+  tok = &tokens[parser->toknext++];
+  tok->start = tok->end = -1;
+  tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+  tok->parent = -1;
+#endif
+  return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+                            const int start, const int end) {
+  token->type = type;
+  token->start = start;
+  token->end = end;
+  token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+                                const size_t len, jsmntok_t *tokens,
+                                const size_t num_tokens) {
+  jsmntok_t *token;
+  int start;
+
+  start = parser->pos;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+    /* In strict mode primitive must be followed by "," or "}" or "]" */
+    case ':':
+#endif
+    case '\t':
+    case '\r':
+    case '\n':
+    case ' ':
+    case ',':
+    case ']':
+    case '}':
+      goto found;
+    default:
+                   /* to quiet a warning from gcc*/
+      break;
+    }
+    if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+      parser->pos = start;
+      return JSMN_ERROR_INVAL;
+    }
+  }
+#ifdef JSMN_STRICT
+  /* In strict mode primitive must be followed by a comma/object/array */
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+#endif
+
+found:
+  if (tokens == NULL) {
+    parser->pos--;
+    return 0;
+  }
+  token = jsmn_alloc_token(parser, tokens, num_tokens);
+  if (token == NULL) {
+    parser->pos = start;
+    return JSMN_ERROR_NOMEM;
+  }
+  jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+  token->parent = parser->toksuper;
+#endif
+  parser->pos--;
+  return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+                             const size_t len, jsmntok_t *tokens,
+                             const size_t num_tokens) {
+  jsmntok_t *token;
+
+  int start = parser->pos;
+
+  /* Skip starting quote */
+  parser->pos++;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    char c = js[parser->pos];
+
+    /* Quote: end of string */
+    if (c == '\"') {
+      if (tokens == NULL) {
+        return 0;
+      }
+      token = jsmn_alloc_token(parser, tokens, num_tokens);
+      if (token == NULL) {
+        parser->pos = start;
+        return JSMN_ERROR_NOMEM;
+      }
+      jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+      token->parent = parser->toksuper;
+#endif
+      return 0;
+    }
+
+    /* Backslash: Quoted symbol expected */
+    if (c == '\\' && parser->pos + 1 < len) {
+      int i;
+      parser->pos++;
+      switch (js[parser->pos]) {
+      /* Allowed escaped symbols */
+      case '\"':
+      case '/':
+      case '\\':
+      case 'b':
+      case 'f':
+      case 'r':
+      case 'n':
+      case 't':
+        break;
+      /* Allows escaped symbol \uXXXX */
+      case 'u':
+        parser->pos++;
+        for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
+             i++) {
+          /* If it isn't a hex character we have an error */
+          if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
+                (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
+                (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+            parser->pos = start;
+            return JSMN_ERROR_INVAL;
+          }
+          parser->pos++;
+        }
+        parser->pos--;
+        break;
+      /* Unexpected symbol */
+      default:
+        parser->pos = start;
+        return JSMN_ERROR_INVAL;
+      }
+    }
+  }
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                        jsmntok_t *tokens, const unsigned int num_tokens) {
+  int r;
+  int i;
+  jsmntok_t *token;
+  int count = parser->toknext;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    char c;
+    jsmntype_t type;
+
+    c = js[parser->pos];
+    switch (c) {
+    case '{':
+    case '[':
+      count++;
+      if (tokens == NULL) {
+        break;
+      }
+      token = jsmn_alloc_token(parser, tokens, num_tokens);
+      if (token == NULL) {
+        return JSMN_ERROR_NOMEM;
+      }
+      if (parser->toksuper != -1) {
+        jsmntok_t *t = &tokens[parser->toksuper];
+#ifdef JSMN_STRICT
+        /* In strict mode an object or array can't become a key */
+        if (t->type == JSMN_OBJECT) {
+          return JSMN_ERROR_INVAL;
+        }
+#endif
+        t->size++;
+#ifdef JSMN_PARENT_LINKS
+        token->parent = parser->toksuper;
+#endif
+      }
+      token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+      token->start = parser->pos;
+      parser->toksuper = parser->toknext - 1;
+      break;
+    case '}':
+    case ']':
+      if (tokens == NULL) {
+        break;
+      }
+      type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+      if (parser->toknext < 1) {
+        return JSMN_ERROR_INVAL;
+      }
+      token = &tokens[parser->toknext - 1];
+      for (;;) {
+        if (token->start != -1 && token->end == -1) {
+          if (token->type != type) {
+            return JSMN_ERROR_INVAL;
+          }
+          token->end = parser->pos + 1;
+          parser->toksuper = token->parent;
+          break;
+        }
+        if (token->parent == -1) {
+          if (token->type != type || parser->toksuper == -1) {
+            return JSMN_ERROR_INVAL;
+          }
+          break;
+        }
+        token = &tokens[token->parent];
+      }
+#else
+      for (i = parser->toknext - 1; i >= 0; i--) {
+        token = &tokens[i];
+        if (token->start != -1 && token->end == -1) {
+          if (token->type != type) {
+            return JSMN_ERROR_INVAL;
+          }
+          parser->toksuper = -1;
+          token->end = parser->pos + 1;
+          break;
+        }
+      }
+      /* Error if unmatched closing bracket */
+      if (i == -1) {
+        return JSMN_ERROR_INVAL;
+      }
+      for (; i >= 0; i--) {
+        token = &tokens[i];
+        if (token->start != -1 && token->end == -1) {
+          parser->toksuper = i;
+          break;
+        }
+      }
+#endif
+      break;
+    case '\"':
+      r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+      if (r < 0) {
+        return r;
+      }
+      count++;
+      if (parser->toksuper != -1 && tokens != NULL) {
+        tokens[parser->toksuper].size++;
+      }
+      break;
+    case '\t':
+    case '\r':
+    case '\n':
+    case ' ':
+      break;
+    case ':':
+      parser->toksuper = parser->toknext - 1;
+      break;
+    case ',':
+      if (tokens != NULL && parser->toksuper != -1 &&
+          tokens[parser->toksuper].type != JSMN_ARRAY &&
+          tokens[parser->toksuper].type != JSMN_OBJECT) {
+#ifdef JSMN_PARENT_LINKS
+        parser->toksuper = tokens[parser->toksuper].parent;
+#else
+        for (i = parser->toknext - 1; i >= 0; i--) {
+          if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
+            if (tokens[i].start != -1 && tokens[i].end == -1) {
+              parser->toksuper = i;
+              break;
+            }
+          }
+        }
+#endif
+      }
+      break;
+#ifdef JSMN_STRICT
+    /* In strict mode primitives are: numbers and booleans */
+    case '-':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case 't':
+    case 'f':
+    case 'n':
+      /* And they must not be keys of the object */
+      if (tokens != NULL && parser->toksuper != -1) {
+        const jsmntok_t *t = &tokens[parser->toksuper];
+        if (t->type == JSMN_OBJECT ||
+            (t->type == JSMN_STRING && t->size != 0)) {
+          return JSMN_ERROR_INVAL;
+        }
+      }
+#else
+    /* In non-strict mode every unquoted value is a primitive */
+    default:
+#endif
+      r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+      if (r < 0) {
+        return r;
+      }
+      count++;
+      if (parser->toksuper != -1 && tokens != NULL) {
+        tokens[parser->toksuper].size++;
+      }
+      break;
+
+#ifdef JSMN_STRICT
+    /* Unexpected char in strict mode */
+    default:
+      return JSMN_ERROR_INVAL;
+#endif
+    }
+  }
+
+  if (tokens != NULL) {
+    for (i = parser->toknext - 1; i >= 0; i--) {
+      /* Unmatched opened object or array */
+      if (tokens[i].start != -1 && tokens[i].end == -1) {
+        return JSMN_ERROR_PART;
+      }
+    }
+  }
+
+  return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser) {
+  parser->pos = 0;
+  parser->toknext = 0;
+  parser->toksuper = -1;
+}
+
+#endif /* JSMN_HEADER */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OFJSMN_H */
index e26b8dc80eae551546563408a760c6a06c8fcdba..b1135ec24f6485ee1d29b6b820157e52cc905603 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2024, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 // of one class of the STL
 #include <list>
 
-#ifdef HAVE_STD_NAMESPACE
 #define OFList std::list
 #define OFListIterator(x) std::list< x >::iterator
 #define OFListConstIterator(x) std::list< x >::const_iterator
-#else
-#define OFList list
-#define OFListIterator(x) list< x >::iterator
-#define OFListConstIterator(x) list< x >::const_iterator
-#endif
-
 #define OFListInsert(InputIterator, T, c, pos, first, last) (c).insert((pos), (first), (last))
 #define OFListRemoveIf(Predicate, T, c, pred) (c).remove_if((pred))
 
 #define OFLIST_TYPENAME
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 /* needed e.g. on Solaris for definition of size_t */
 #include <sys/types.h>
-#endif
 END_EXTERN_C
 
 // OFListLinkBase, OFListLink and OFListBase are classes for internal
index 288503ad1a6dd8218f5641fbceea17d364c52702..6b50b3dee86f6db31faaaa1d4baf7022cce1c4a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015, OFFIS e.V.
+ *  Copyright (C) 2015-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -42,6 +42,7 @@ public:
 
     static OFBool (isinf) (float f);
     static OFBool (isinf) (double d);
+    static double (sqrt) (double d);
     template<typename Integer>
     static inline OFTypename OFenable_if<OFis_integral<Integer>::value,OFBool>::type
     (isinf) ( const Integer i ) { return (isinf) ( OFstatic_cast( double, i ) ); }
@@ -77,6 +78,12 @@ public:
      */
     static OFBool isinf( double d );
 
+    /** Computes the square root of a floating point number.
+     *  @param d the floating point value to inspect.
+     *  @return the square root of d.
+     */
+    static double sqrt( double d );
+
     /** Casts the argument to double and calls OFMath::isinf(double) on the result.
      *  @param i an integer, i.e. <kbd>OFis_integral<Integer>::value</kbd> equals <kbd>OFTrue</kbd>.
      *  @return OFMath::isinf(OFstatic_cast(double,i)).
index d7a4e96db6ce530e54ef11498e04039f6ae7a3d6..3559e201c89e0773db8c7d6b0676b09b831fdef9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2012-2017, OFFIS e.V.
+ *  Copyright (C) 2012-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -40,11 +40,7 @@ using OFunique_ptr = std::unique_ptr<ARGS...>;
 #if defined HAVE_SYNC_ADD_AND_FETCH && defined HAVE_SYNC_SUB_AND_FETCH
 #define OF_SHARED_PTR_COUNTER_TYPE size_t
 #elif defined HAVE_INTERLOCKED_INCREMENT && defined HAVE_INTERLOCKED_DECREMENT
-#if _MSC_VER <= 1200
-#define OF_SHARED_PTR_COUNTER_TYPE LONG
-#else
 #define OF_SHARED_PTR_COUNTER_TYPE volatile LONG
-#endif
 #else
 #define OF_SHARED_PTR_COUNTER_TYPE size_t
 #define OF_SHARED_PTR_NEED_MUTEX 1
index 9f53c75bc8a9f917ad72017ac4f2d9ef6e3bcc45..9259f1ed16652c9e35d900c1ab51a04f56f89601 100644 (file)
@@ -33,7 +33,7 @@
 
 // include <type_traits> for "std::is_default_constructible"
 // to recover from compiler insanity (Visual Studio 12+).
-#if defined(_MSC_VER) && _MSC_VER >= 1700
+#if defined(_MSC_VER)
 #include <type_traits>
 #endif
 
@@ -136,25 +136,10 @@ class OFdefault_optional_traits
     template<typename X>
     static yes_type sfinae(consume<sizeof *new X>*);
 #elif defined(_MSC_VER)
-#if _MSC_VER < 1700
-    // Workaround bug in Visual Studio.
-    // On these broken compilers, the argument is not evaluated
-    // unless we require them to evaluate it for choosing which
-    // specialization should be instantiated.
-    template<size_t,size_t>
-    struct consume{};
-    template<size_t X>
-    struct consume<X,X> { typedef void type; };
-    // sfinae overload working for value-initializable Xs, that's as
-    // close as we get on these broken compilers
-    template<typename X>
-    static yes_type sfinae(typename consume<sizeof X(),sizeof X()>::type*);
-#else
     // Visual Studio 2012 is completely broken, but it has std::is_default_constructible
     // Note: this tests constructibility, but not if WE can construct this.
     template<typename X>
     static yes_type sfinae(typename OFenable_if<std::is_default_constructible<X>::value>::type*);
-#endif // _MSC_VER
 #endif // HAVE_DEFAULT_CONSTRUCTOR_DETECTION_VIA_SFINAE
     // most general sfinae overload, chosen only if everything else fails
     template<typename X>
index d55a001798920b4715319f9fbc0fbb88e5daac82..27bc87b615600771d9519ce743b02efa641ba006 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2018, OFFIS e.V.
+ *  Copyright (C) 2018-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -40,12 +40,10 @@ public:
   /// destructor
   virtual ~OFRandom() {}
 
-#ifndef OF_NO_UINT64
   /** return a random Uint64 value
    *  @return random unsigned 64-bit number
    */
   Uint64 getRND64();
-#endif
 
   /** return a random Uint32 value
    *  @return random unsigned 32-bit number
diff --git a/ofstd/include/dcmtk/ofstd/ofsha256.h b/ofstd/include/dcmtk/ofstd/ofsha256.h
new file mode 100644 (file)
index 0000000..1d80d70
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  ofstd
+ *
+ *  Author:  Marco Eichelberg, based on code by Brad Conte (brad AT bradconte.com) in FreeBSD
+ *
+ *  Purpose: Implementation of SHA-256
+ *
+ */
+
+#ifndef OFSHA256_H
+#define OFSHA256_H
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofdefine.h"
+#include "dcmtk/ofstd/oftypes.h"
+
+
+#define SHA256_BLOCK_SIZE 32            // SHA-256 outputs a 32 byte digest
+
+class DCMTK_OFSTD_EXPORT OFSHA256
+{
+public:
+    /// default constructor
+    OFSHA256();
+
+    /// initialize instance, i.e. reset to initial state
+    void init();
+
+    /** feed bytes to the hash algorithm
+     *  @param data bytes to feed
+     *  @param len number of bytes
+     */
+    void update(const void *data, size_t len);
+
+   /** finalize and return hash
+    *  @param hash pointer to memory block of at least 32 bytes.
+    *    The SHA-256 hash is copied into this block.
+    */
+    void final(void *hash);
+
+private:
+
+    /// transform hash key state based on the content of the data buffer
+    void transform();
+
+    /// data buffer
+    Uint8 data_[64];
+
+    /// number of bytes in data buffer
+    Uint32 datalen_;
+
+    /// total number of bits that have been fed into the hash algorithm
+    unsigned long long bitlen_;
+
+    /// state information for the hash key
+    Uint32 state_[8];
+};
+
+#endif
index 7451067bdc8806f21261e316eef655363dedfddf..66b56eba9955d369f01a5afe79d8de173d5c643c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2017-2021, OFFIS e.V.
+ *  Copyright (C) 2017-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -35,9 +35,7 @@ END_EXTERN_C
 #endif
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_SOCKET_H
 /* some systems (such as DEC Ultrix) don't protect <sys/socket.h> from double inclusion */
 #ifndef DCOMPAT_SYS_SOCKET_H_
@@ -65,7 +63,7 @@ struct sockaddr;
 struct sockaddr_in;
 struct sockaddr_in6;
 
-/** A simple wrapper class for a struct sockaddr_storage object 
+/** A simple wrapper class for a struct sockaddr_storage object
  *  that can be used to store an TCP/IPv4 (struct sockaddr_in) or TCP/IPv6
  *  (struct sockaddr_in6) address.
  */
index ace0cdba68798c0f923cc14571a04e91213470ae..265f51d952f7689ea934105c1afa5341cfd3c325 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2024, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -45,15 +45,15 @@ END_EXTERN_C
 #endif
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>  /* for size_t */
-#endif
 END_EXTERN_C
 
 /* Check if we are using glibc in a version where readdir() is known to be
  * thread-safe and where readdir_r() is deprecated.
+ * Android uses a different libc implementation but also guarantees that
+ * readdir() is thread-safe and marks readdir_r() as deprecated.
  */
-#if defined(__GLIBC__) && (((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 24)) || (__GLIBC__ >= 3))
+#if (defined(__GLIBC__) && (((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 24)) || (__GLIBC__ >= 3))) || defined(__ANDROID__)
 #define READDIR_IS_THREADSAFE
 #endif
 
@@ -720,7 +720,7 @@ class DCMTK_OFSTD_EXPORT OFStandard
      *  can be decoded back to its exact size.
      *  If the input data is NULL an error code (EC_IllegalParameter) is returned.
      ** @param out output stream used for the base64 encoded data
-     *  @param data buffer with binary data to be encoded (big endian required!)
+     *  @param data buffer with binary data to be encoded
      *  @param length length of the input data buffer (in bytes)
      *  @param width maximum number of characters per line in the output stream
      *    (default: 0 = no line breaks, typical for MIME = 72)
@@ -737,7 +737,7 @@ class DCMTK_OFSTD_EXPORT OFStandard
      *  even multiple of 3.  A special character ('=') is used to denote padding so that the output
      *  can be decoded back to its exact size.
      *  If the input data is NULL an empty string is returned.
-     ** @param data buffer with binary data to be encoded (big endian required!)
+     ** @param data buffer with binary data to be encoded
      *  @param length length of the input data buffer (in bytes)
      *  @param result reference to resulting string variable (Base64 encoded)
      *  @param width maximum number of characters per line in the output string
@@ -758,7 +758,7 @@ class DCMTK_OFSTD_EXPORT OFStandard
      *      and has to to be freed (using "delete[]") by the caller!  Do not pass a pointer to an
      *      already allocated buffer to this function, the caller does not know the exact size anyway.
      ** @param data Base64 encoded input data (possibly padded with '=' at the end)
-     *  @param result receives pointer to resulting buffer with binary data (big endian encoded)
+     *  @param result receives pointer to resulting buffer with binary data
      ** @return length of the resulting binary data (0 if an error occurred, in this case the buffer
      *    is deleted internally)
      */
@@ -827,7 +827,7 @@ class DCMTK_OFSTD_EXPORT OFStandard
      /** @name ftoa() processing flags.
       *  These flags can be combined by bit-wise or.
       */
-     //@{
+     ///@{
 
      /// Use scientific format (equivalent to %e or %E in printf),
      /// instead of the default, which is equivalent to %g or %G.
@@ -854,7 +854,7 @@ class DCMTK_OFSTD_EXPORT OFStandard
      /// pad with zeroes instead of blanks
      static const unsigned int ftoa_zeropad;
 
-     //@}
+     ///@}
 
     /** makes the current process sleep until seconds seconds have
      *  elapsed or a signal arrives which is not ignored
index bbf4fb78f645e4c02734ee8a38806bf01a80b689..03dc2f3205659c44885c02feb78f577de3e6125e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -37,11 +37,7 @@ using namespace std;
 
 // define STD_NAMESPACE to std:: if the standard namespace exists
 #ifndef STD_NAMESPACE
-#ifdef HAVE_STD_NAMESPACE
 #define STD_NAMESPACE std::
-#else
-#define STD_NAMESPACE
-#endif
 #endif
 
 /* Print an error message in case some user code still uses the now unsupported
index 055982924e99b9d411a812dd062f15c34d478957..9bf575b0b2a536042228bced54e87a6dc230ba2b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2024, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 // define STD_NAMESPACE to std:: if the standard namespace exists
 #ifndef STD_NAMESPACE
-#ifdef HAVE_STD_NAMESPACE
 #define STD_NAMESPACE std::
-#else
-#define STD_NAMESPACE
-#endif
 #endif
 
 #define OFendl STD_NAMESPACE endl
diff --git a/ofstd/include/dcmtk/ofstd/ofstrhlp.h b/ofstd/include/dcmtk/ofstd/ofstrhlp.h
new file mode 100644 (file)
index 0000000..1ef8bc2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  ofstd
+ *
+ *  Author:  Marco Eichelberg
+ *
+ *  Purpose: Helper functions to convert between std::string and OFString
+ *
+ */
+
+#ifndef OFSTRHLP_H
+#define OFSTRHLP_H
+
+#include "dcmtk/config/osconfig.h"     /* include OS specific configuration first */
+#include "dcmtk/ofstd/ofstring.h"      /* for class OFString */
+#include <string>                      /* for std::string */
+
+/** convert OFString to std::string.
+ *  This helper function converts an OFString object into an equivalent std::string.
+ *  @param arg string to convert
+ *  @return string as std::string object
+ */
+inline STD_NAMESPACE string OFString_to_std_string(const OFString& arg)
+{
+#ifdef HAVE_STL_STRING
+  // OFString is just a typedef for std::string
+  return arg;
+#else
+  return STD_NAMESPACE string(arg.c_str(), arg.length());
+#endif
+}
+
+/** convert std::string to OFString.
+ *  This helper function converts a std::string object into an equivalent OFString.
+ *  @param arg string to convert
+ *  @return string as OFString object
+ */
+inline OFString std_string_to_OFString(const STD_NAMESPACE string& arg)
+{
+#ifdef HAVE_STL_STRING
+  // OFString is just a typedef for std::string
+  return arg;
+#else
+  return OFString(arg.c_str(), arg.length());
+#endif
+}
+
+#endif /* OFSTRHLP_H */
index f0454062a96543f64bfc3cc719acb1abc95f4b37..2bb173345e720ba5d0b5c0845dffb2b68cc55e28 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2016, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 #include "dcmtk/ofstd/oftypes.h"     /* for OFBool */
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for O_RDWR */
-#endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>       /* needed on Solaris for O_RDWR */
-#endif
 END_EXTERN_C
 
 /** this class manages the lifetime of a temporary file. The file will be
index fe421262393c0d4dbb812b05dc20c8acda0e6886..31975854246beecce6cc8978fe863259ecd05580 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2022, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This code is inspired by quicktest.
@@ -514,7 +514,7 @@ public: \
  *  These macros can be used for doing various checks in test cases. In case
  *  their check fails, they emit a descriptive message explaining the problem.
  */
-//@{
+///@{
 
 /** Check if a condition is true. Can only be used inside OFTEST().
  *  @param condition condition to check
@@ -561,6 +561,6 @@ public: \
         OFTestManager::instance().currentTest().recordFailure(__FILE__, __LINE__, str___); \
     } while (0)
 
-//@}
+///@}
 
 #endif
index f17e18f4fb59c28b0e3e9695405777f989046791..d1125bb8c08f0dfe67b959be1f2b2c39e059dbe2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -26,9 +26,7 @@
 #include "dcmtk/config/osconfig.h"
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>    /* for struct time_t */
-#endif
+#include <sys/types.h>    /* for struct time_t */
 END_EXTERN_C
 
 #include "dcmtk/ofstd/ofstring.h"      /* for class OFString */
index 0464cf8c18231426b3c737ea5c4dfc508b8163dd..ee9875f2af895e53c25bfab5d3fe1d9fecb31453 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2024, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -79,9 +79,7 @@ inline std::ostream& operator<<( std::ostream& o, OFnullptr_t /* unused */ )
 
 #include <cstddef>
 BEGIN_EXTERN_C
-#ifdef HAVE_STDINT_H
 #include <stdint.h>
-#endif
 #include <inttypes.h>
 END_EXTERN_C
 
@@ -132,7 +130,7 @@ typedef long          Sint64;
 typedef OFlonglong    Sint64;
 #else
 /* we have not found any 64-bit signed integer type */
-#define OF_NO_SINT64 1
+#error unsupported platform (no 64-bit signed integer type)
 #endif
 
 #ifdef HAVE_UINT64_T
@@ -146,7 +144,7 @@ typedef unsigned long Uint64;
 typedef OFulonglong   Uint64;
 #else
 /* we have not found any 64-bit unsigned integer type */
-#define OF_NO_UINT64 1
+#error unsupported platform (no 64-bit unsigned integer type)
 #endif
 
 #if SIZEOF_VOID_P == 2
@@ -156,17 +154,9 @@ typedef Uint16 OFuintptr_t;
 typedef Sint32 OFintptr_t;
 typedef Uint32 OFuintptr_t;
 #elif SIZEOF_VOID_P == 8
-#ifndef OF_NO_SINT64
 typedef Sint64 OFintptr_t;
-#else
-#error unsupported platform (64-Bit pointers but no 64-Bit signed integer type)
-#endif
-#ifndef OF_NO_UINT64
 typedef Uint64 OFuintptr_t;
 #else
-#error unsupported platform (64-Bit pointers but no 64-Bit unsigned integer type)
-#endif
-#else
 #error Unsupported platform (invalid pointer size)
 #endif
 
index e4065611521dd7c8cdfee2f4935d6a718c9333b9..ce7716df52661ec0029f2b88e05c05ad0ad8953c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2010-2024, OFFIS e.V.
+ *  Copyright (C) 2010-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 // Use the standard template library (STL) vector class.
 #include <vector>
-
-#ifdef HAVE_STD_NAMESPACE
 #define OFVector std::vector
-#else
-#define OFVector vector
-#endif
 
 #else
 
index b705daef81e08f5ebf2df5553e2f7cab63363641..cde444d5b7c976a563adcfa4010bfd8e0a1c9095 100644 (file)
@@ -1,5 +1,5 @@
 # create library from source files
-DCMTK_ADD_LIBRARY(ofstd 
+DCMTK_ADD_LIBRARY(ofstd
   ofchrenc.cc
   ofcmdln.cc
   ofconapp.cc
@@ -14,6 +14,7 @@ DCMTK_ADD_LIBRARY(ofstd
   offilsys.cc
   offname.cc
   ofipc.cc
+  ofjsmn.cc
   oflist.cc
   ofstd.cc
   ofstring.cc
@@ -29,6 +30,7 @@ DCMTK_ADD_LIBRARY(ofstd
   ofrand.cc
   ofwhere.c
   ofstub.cc
+  ofsha256.cc
 )
 
 DCMTK_TARGET_LINK_LIBRARIES(ofstd config ${CHARSET_CONVERSION_LIBS} ${SOCKET_LIBS} ${THREAD_LIBS} ${WIN32_STD_LIBRARIES})
index 4bcc37217b720c583ba24d29a84ff33e4a33bd7d..54042dfc8a7c0cdacb7bcc738801594888c5ee90 100644 (file)
@@ -142,6 +142,11 @@ ofipc.o: ofipc.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/ofstd/oflist.h ../include/dcmtk/ofstd/ofstd.h \
  ../include/dcmtk/ofstd/oftraits.h ../include/dcmtk/ofstd/oflimits.h \
  ../include/dcmtk/ofstd/oferror.h
+ofjsmn.o: ofjsmn.cc ../include/dcmtk/ofstd/ofjsmn.h \
+ ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/ofstd/oftypes.h ../include/dcmtk/ofstd/ofdefine.h \
+ ../include/dcmtk/ofstd/ofcast.h ../include/dcmtk/ofstd/ofexport.h \
+ ../include/dcmtk/ofstd/ofstdinc.h
 oflist.o: oflist.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/ofstd/oflist.h ../include/dcmtk/ofstd/oftypes.h \
  ../include/dcmtk/ofstd/ofdefine.h ../include/dcmtk/ofstd/ofcast.h \
@@ -163,6 +168,10 @@ ofrand.o: ofrand.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/ofstd/diag/useafree.def \
  ../include/dcmtk/ofstd/diag/pop.def ../include/dcmtk/ofstd/oflimits.h \
  ../include/dcmtk/ofstd/oferror.h
+ofsha256.o: ofsha256.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/ofstd/ofsha256.h ../include/dcmtk/ofstd/ofdefine.h \
+ ../include/dcmtk/ofstd/ofcast.h ../include/dcmtk/ofstd/ofexport.h \
+ ../include/dcmtk/ofstd/oftypes.h ../include/dcmtk/ofstd/ofstdinc.h
 ofsockad.o: ofsockad.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/ofstd/ofsockad.h ../include/dcmtk/ofstd/ofdefine.h \
  ../include/dcmtk/ofstd/ofcast.h ../include/dcmtk/ofstd/ofexport.h \
index bb720dc9cb320314b4c7fc5f5c8df65fbf888627..50a1a6c2bcaf47dce9a8d8091cb7e6fe425dad17 100644 (file)
@@ -21,7 +21,7 @@ objs = oflist.o ofstring.o ofcmdln.o ofconapp.o offname.o ofconsol.o ofthread.o
        ofcond.o ofstd.o ofcrc32.o ofdate.o oftime.o ofdatime.o oftimer.o \
        ofconfig.o ofchrenc.o oftempf.o ofxml.o ofuuid.o offile.o offilsys.o \
        ofmath.o oferror.o ofsockad.o ofrand.o ofstrutl.o ofipc.o ofwhere.o \
-    ofstub.o
+       ofstub.o ofsha256.o ofjsmn.o
 
 library = libofstd.$(LIBEXT)
 
index 21b3b86b490d9dbb1123f0a01d6a4fd74b206016..d2d80e8e01569262b1d4eb60134792ff11bfe238 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2000-2021, OFFIS e.V.
+ *  Copyright (C) 2000-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -32,9 +32,7 @@ END_EXTERN_C
 
 
 BEGIN_EXTERN_C
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>
 #endif
@@ -154,7 +152,7 @@ void OFConsole::mergeStderrStdout()
         }
     }
 
-#ifndef __BORLANDC__  /* setvbuf on stdout/stderr does not work with Borland C++ */
+#ifndef HAVE_CLASSIC_BORLAND_COMPILER  /* setvbuf on stdout/stderr does not work with Borland C++ */
     /* set stdout and stderr to unbuffered mode */
     if (setvbuf(stdout, NULL, _IONBF, 0 ) != 0 )
     {
@@ -166,7 +164,7 @@ void OFConsole::mergeStderrStdout()
         OFConsole::instance().lockCerr() << "Unable to switch stderr to unbuffered mode" << OFendl;
         OFConsole::instance().unlockCerr();
     }
-#endif /* __BORLANDC__ */
+#endif /* HAVE_CLASSIC_BORLAND_COMPILER */
 }
 
 
@@ -181,7 +179,7 @@ void OFConsole::unmergeStderrStdout()
             OFConsole::instance().unlockCerr();
         }
 
-#ifndef __BORLANDC__
+#ifndef HAVE_CLASSIC_BORLAND_COMPILER
         /* switch stdout to buffered mode */
         if (setvbuf(stdout, NULL, _IOFBF, BUFSIZ ) != 0 )
         {
@@ -189,7 +187,7 @@ void OFConsole::unmergeStderrStdout()
             OFConsole::instance().unlockCerr();
 
         }
-#endif /* __BORLANDC__ */
+#endif /* HAVE_CLASSIC_BORLAND_COMPILER */
     }
 }
 
index 308167a820c2217ee0ca78877056a1244d849ac2..8ffb171f19f4a036cce6b39d0d7515406f399bbb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2002-2021, OFFIS e.V.
+ *  Copyright (C) 2002-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 #include "dcmtk/config/osconfig.h"
 
-#ifdef HAVE_SYS_TYPES_H
 BEGIN_EXTERN_C
 #include <sys/types.h>    /* for struct time_t */
 END_EXTERN_C
-#endif
 
 #include "dcmtk/ofstd/ofdatime.h"
 #include "dcmtk/ofstd/ofstdinc.h"
index 1cc96590d7e5f4ac8be2429350c3f5b8f90f8ce2..d51dc4ccca600e2cffe97f8fc84d309af2a2672e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2021-2024, OFFIS e.V.
+ *  Copyright (C) 2021-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -31,9 +31,7 @@
 #include <io.h>
 #else // _WIN32
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 #ifdef HAVE_SYS_FILE_H
 #include <sys/file.h>  // for struct DIR, opendir()
 #endif
@@ -43,8 +41,10 @@ BEGIN_EXTERN_C
 END_EXTERN_C
 /* Check if we are using glibc in a version where readdir() is known to be
  * thread-safe and where readdir_r() is deprecated.
+ * Android uses a different libc implementation but also guarantees that
+ * readdir() is thread-safe and marks readdir_r() as deprecated.
  */
-#if defined(__GLIBC__) && (((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 24)) || (__GLIBC__ >= 3))
+#if (defined(__GLIBC__) && (((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 24)) || (__GLIBC__ >= 3))) || defined(__ANDROID__)
 #define READDIR_IS_THREADSAFE
 #endif
 #endif // _WIN32
index a56a7e1b586464da9986007ddd4a5ec2b2f6b9c7..cf14d0b76ffd1dc1ee0ab15b1cfc1f6ae813b983 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2022, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
 
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>    /* for time_t */
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat() */
-#endif
 END_EXTERN_C
 
 /* give up after this number of unsuccessful attempts to create a unique filename */
index 2ecbb76c7464eaf8841cf3f1f07145bc4390f3ab..ff9ebff2d71f6bb15489ee5a2f29693516d604ca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2022-2024, OFFIS e.V.
+ *  Copyright (C) 2022-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -38,18 +38,12 @@ BEGIN_EXTERN_C
 #if defined(HAVE_MQUEUE_H) && !defined(__FreeBSD__)
 #include <mqueue.h>
 #endif
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
 #ifdef HAVE_SYS_MSG_H
 #include <sys/msg.h>
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
-#endif
 
 #ifdef DCMTK_HAVE_POLL
 #include <poll.h>
diff --git a/ofstd/libsrc/ofjsmn.cc b/ofstd/libsrc/ofjsmn.cc
new file mode 100644 (file)
index 0000000..31deecb
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *
+ *  Copyright (C) 2024-2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  ofstd
+ *
+ *  Author:  Tingyan Xu
+ *
+ *  Purpose: Implementation of JSON parser library
+ *
+ */
+
+#include "dcmtk/ofstd/ofjsmn.h"
index 927cc132cef190be8ea85cf16442c036622a67ee..790fb16bfdcb1207d5c4b5358fb85a4444fe09ac 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2015-2016, OFFIS e.V.
+ *  Copyright (C) 2015-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -45,3 +45,8 @@ OFBool OFMath::isinf( double d )
 {
   return (dcmtk_config_math::isinf)( d );
 }
+
+double OFMath::sqrt(double d)
+{
+  return (dcmtk_config_math::sqrt)( d );
+}
index 45401c4dd6f0e535b2a66050eba8c1c57d6bb96e..563bb0d34e0d869b188242e8594e2556f1fb1a76 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2021, OFFIS e.V.
+ *  Copyright (C) 2021-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -186,7 +186,6 @@ Uint16 OFRandom::getRND16()
   return OFstatic_cast(Uint16, getRND32());
 }
 
-#ifndef OF_NO_UINT64
 Uint64 OFRandom::getRND64()
 {
   // get a 32-bit random number
@@ -197,4 +196,3 @@ Uint64 OFRandom::getRND64()
   result |= getRND32();
   return result;
 }
-#endif
diff --git a/ofstd/libsrc/ofsha256.cc b/ofstd/libsrc/ofsha256.cc
new file mode 100644 (file)
index 0000000..b18d6c2
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *
+ *  Copyright (C) 2025, OFFIS e.V.
+ *  All rights reserved.  See COPYRIGHT file for details.
+ *
+ *  This software and supporting documentation were developed by
+ *
+ *    OFFIS e.V.
+ *    R&D Division Health
+ *    Escherweg 2
+ *    D-26121 Oldenburg, Germany
+ *
+ *
+ *  Module:  ofstd
+ *
+ *  Author:     Marco Eichelberg, based on code by Brad Conte (brad AT bradconte.com) in FreeBSD.
+ *  Disclaimer: This code is presented "as is" without any guarantees.
+ *  Details:    Implementation of the SHA-256 hashing algorithm.
+ *              SHA-256 is one of the three algorithms in the SHA2
+ *              specification. The others, SHA-384 and SHA-512, are not
+ *              offered in this implementation.
+ *              Algorithm specification can be found here:
+ *              http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+ *              This implementation internally uses little endian byte order.
+ */
+
+#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
+#include "dcmtk/ofstd/ofsha256.h"
+#include <cstring>
+
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+static const Uint32 k[64] = {
+    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+
+void OFSHA256::transform()
+{
+    Uint32 a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+    for (i = 0, j = 0; i < 16; ++i, j += 4)
+        m[i] = (OFstatic_cast(Uint32, data_[j]) << 24) | (OFstatic_cast(Uint32, data_[j + 1]) << 16) | (OFstatic_cast(Uint32, data_[j + 2]) << 8) | (OFstatic_cast(Uint32, data_[j + 3]));
+    for ( ; i < 64; ++i)
+        m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+    a = state_[0];
+    b = state_[1];
+    c = state_[2];
+    d = state_[3];
+    e = state_[4];
+    f = state_[5];
+    g = state_[6];
+    h = state_[7];
+
+    for (i = 0; i < 64; ++i) {
+        t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+        t2 = EP0(a) + MAJ(a,b,c);
+        h = g;
+        g = f;
+        f = e;
+        e = d + t1;
+        d = c;
+        c = b;
+        b = a;
+        a = t1 + t2;
+    }
+
+    state_[0] += a;
+    state_[1] += b;
+    state_[2] += c;
+    state_[3] += d;
+    state_[4] += e;
+    state_[5] += f;
+    state_[6] += g;
+    state_[7] += h;
+}
+
+
+OFSHA256::OFSHA256()
+{
+    init();
+}
+
+void OFSHA256::init()
+{
+    datalen_ = 0;
+    bitlen_ = 0;
+    state_[0] = 0x6a09e667;
+    state_[1] = 0xbb67ae85;
+    state_[2] = 0x3c6ef372;
+    state_[3] = 0xa54ff53a;
+    state_[4] = 0x510e527f;
+    state_[5] = 0x9b05688c;
+    state_[6] = 0x1f83d9ab;
+    state_[7] = 0x5be0cd19;
+}
+
+void OFSHA256::update(const void *data, size_t len)
+{
+    if (data == NULL) return;
+    const Uint8 *uint8data = OFreinterpret_cast(const Uint8 *, data);
+    for (size_t i = 0; i < len; ++i) {
+        data_[datalen_] = uint8data[i];
+        datalen_++;
+        if (datalen_ == 64) {
+            transform();
+            bitlen_ += 512;
+            datalen_ = 0;
+        }
+    }
+}
+
+void OFSHA256::final(void *hash)
+{
+    if (hash == NULL) return;
+
+    Uint8 *uint8hash = OFreinterpret_cast(Uint8 *, hash);
+    Uint32 i, j;
+    i = datalen_;
+
+    // Pad whatever data is left in the buffer.
+    if (datalen_ < 56) {
+        data_[i++] = 0x80;
+        while (i < 56)
+            data_[i++] = 0x00;
+    }
+    else {
+        data_[i++] = 0x80;
+        while (i < 64)
+            data_[i++] = 0x00;
+        transform();
+        memset(data_, 0, 56);
+    }
+
+    // Append to the padding the total message's length in bits and transform.
+    bitlen_ += datalen_ * 8;
+    data_[63] = OFstatic_cast(Uint8, bitlen_);
+    data_[62] = OFstatic_cast(Uint8,(bitlen_ >> 8));
+    data_[61] = OFstatic_cast(Uint8,(bitlen_ >> 16));
+    data_[60] = OFstatic_cast(Uint8,(bitlen_ >> 24));
+    data_[59] = OFstatic_cast(Uint8,(bitlen_ >> 32));
+    data_[58] = OFstatic_cast(Uint8,(bitlen_ >> 40));
+    data_[57] = OFstatic_cast(Uint8,(bitlen_ >> 48));
+    data_[56] = OFstatic_cast(Uint8,(bitlen_ >> 56));
+    transform();
+
+    // Since this implementation uses little endian byte ordering and SHA uses big endian,
+    // reverse all the bytes when copying the final state to the output hash.
+    for (i = j = 0; i < 8; ++i, ++j) {
+        uint8hash[j++] = (state_[i] >> 24) & 0xff;
+        uint8hash[j++] = (state_[i] >> 16) & 0xff;
+        uint8hash[j++] = (state_[i] >> 8) & 0xff;
+        uint8hash[j]   = state_[i] & 0xff;
+    }
+}
index 748932ad47e42cdf68a940097c10ef8326139816..3524695ae812ace22f147dd87228a379d51fa0e3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2001-2024, OFFIS e.V.
+ *  Copyright (C) 2001-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -121,15 +121,11 @@ END_EXTERN_C
 #include <sstream>
 
 BEGIN_EXTERN_C
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>    /* for stat() */
-#endif
 #ifdef HAVE_IO_H
 #include <io.h>          /* for access() on Win32 */
 #endif
-#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>   /* for opendir() and closedir() */
-#endif
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>      /* for opendir() and closedir() */
 #else
@@ -225,8 +221,9 @@ END_EXTERN_C
 #if !defined(ENABLE_OLD_OFSTD_FTOA_IMPLEMENTATION) && !defined(ENABLE_IOSTREAM_BASED_FTOA_IMPLEMENTATION) && !defined(ENABLE_CSTDIO_BASED_FTOA_IMPLEMENTATION)
 #ifdef _WIN32
 // on Windows, the iostream-based implementation of atof is extremely slow,
-// and we do have a locale independent version of sscanf. Use this version.
-#define ENABLE_CSTDIO_BASED_ATOF_IMPLEMENTATION
+// and we do have a locale independent version of sprintf, called _snprintf_s_l.
+// Use this version.
+#define ENABLE_CSTDIO_BASED_FTOA_IMPLEMENTATION
 #else
 // on other platforms, we assume that the iobased-implementation, being the
 // cleanest one, is appropriate. This is known to be the case for gcc and clang with glibc.
@@ -349,37 +346,7 @@ int OFStandard::vsnprintf(char *str, size_t size, const char *format, va_list ap
     return ::vsnprintf(str, size, format, ap);
 #endif /* _MSC_VER < 1900 */
 #else /* _MSC_VER */
-#ifdef HAVE_VSNPRINTF
     return ::vsnprintf(str, size, format, ap);
-#else /* HAVE_VSNPRINTF */
-#ifdef DCMTK_ENABLE_UNSAFE_VSNPRINTF
-    // This implementation internally uses vsprintf (which is inherently unsafe).
-    // It allocates a buffer that is 1 kByte larger than "size",
-    // formats the string into that buffer, and then uses strlcpy() to
-    // copy the formatted string into the output buffer, truncating if necessary.
-    // This will work in most cases, since few snprintf calls should overrun
-    // the provided buffer by more than 1K, but it can be easily abused by
-    // a malicious attacker to cause a buffer overrun.
-    //
-    // Therefore, this implementation should only be used as a "last resort"
-    // and we strongly advise against using it in production code.
-    // The macro "DCMTK_ENABLE_UNSAFE_VSNPRINTF" must explicitly be defined
-    // by the used to enable this implementation.
-    int count = -1;
-    if (size != 0)
-    {
-      char *buf = new char[size+1024];
-      count = ::vsprintf(buf, format, ap);
-      OFStandard::strlcpy(str, buf, size);
-      delete[] buf;
-    }
-    return count;
-#warning Using unsafe implementation of vsnprintf(3)
-#else /* DCMTK_ENABLE_UNSAFE_VSNPRINTF */
-    return -1;
-#error vsnprintf(3) not found. Use different compiler or compile with DCMTK_ENABLE_UNSAFE_VSNPRINTF (unsafe!)
-#endif /* DCMTK_ENABLE_UNSAFE_VSNPRINTF */
-#endif /* HAVE_VSNPRINTF */
 #endif /* _MSC_VER */
 }
 
@@ -472,7 +439,6 @@ OFBool OFStandard::pathExists(const OFFilename &pathName)
     /* check for valid path name (avoid NULL or empty string) */
     if (!pathName.isEmpty())
     {
-#ifdef HAVE_ACCESS
         /* check existence with "access()" */
 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
         /* check whether to use the wide-char version of the API function */
@@ -481,31 +447,6 @@ OFBool OFStandard::pathExists(const OFFilename &pathName)
         else
 #endif
             result = (access(pathName.getCharPointer(), F_OK) == 0);
-#else /* HAVE_ACCESS */
-#ifdef HAVE_WINDOWS_H
-        /* get file attributes */
-        DWORD fileAttr;
-#if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
-        /* check whether to use the wide-char version of the API function */
-        if (pathName.usesWideChars())
-            fileAttr = GetFileAttributesW(pathName.getWideCharPointer());
-        else
-#endif
-            fileAttr = GetFileAttributes(pathName.getCharPointer());
-        result = (fileAttr != 0xffffffff);
-#else /* HAVE_WINDOWS_H */
-#ifdef HAVE_SYS_STAT_H
-        /* check existence with "stat()" */
-        struct stat stat_buf;
-        result = (stat(pathName.getCharPointer(), &stat_buf) == 0);
-#else
-        /* try to open the given "file" (or directory) in read-only mode */
-        OFFile file;
-        result = file.fopen(pathName, "r");
-        file.fclose();
-#endif /* HAVE_SYS_STAT_H */
-#endif /* HAVE_WINDOWS_H */
-#endif /* HAVE_ACCESS */
     }
     return result;
 }
@@ -582,7 +523,6 @@ OFBool OFStandard::isReadable(const OFFilename &pathName)
     /* check for valid path name (avoid NULL or empty string) */
     if (!pathName.isEmpty())
     {
-#ifdef HAVE_ACCESS
         /* check whether the path is readable using "access()" */
 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
         /* check whether to use the wide-char version of the API function */
@@ -591,11 +531,6 @@ OFBool OFStandard::isReadable(const OFFilename &pathName)
         else
 #endif
             result = (access(pathName.getCharPointer(), R_OK) == 0);
-#else /* HAVE_ACCESS */
-        /* try to open the given "file" (or directory) in read-only mode */
-        OFFile file;
-        result = file.fopen(pathName, "r");
-#endif /* HAVE_ACCESS */
 }
     return result;
 }
@@ -607,7 +542,6 @@ OFBool OFStandard::isWriteable(const OFFilename &pathName)
     /* check for valid path name (avoid NULL or empty string) */
     if (!pathName.isEmpty())
     {
-#ifdef HAVE_ACCESS
         /* check whether the path is writable using "access()" */
 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
         /* check whether to use the wide-char version of the API function */
@@ -616,11 +550,6 @@ OFBool OFStandard::isWriteable(const OFFilename &pathName)
         else
 #endif
             result = (access(pathName.getCharPointer(), W_OK) == 0);
-#else /* HAVE_ACCESS */
-        /* try to open the given "file" (or directory) in write mode */
-        OFFile file;
-        result = file.fopen(pathName, "w");
-#endif /* HAVE_ACCESS */
     }
     return result;
 }
@@ -1989,6 +1918,13 @@ double OFStandard::atof(const char *s, OFBool *success)
         return OFnumeric_limits<double>::quiet_NaN();
     }
 
+    // handle negative NaN as a special case, since iostream does not
+    if ((ss.length() >= 4) && (ss[0] == '-') && (ss[1] == 'n' || ss[1] == 'N') && (ss[2] == 'a' || ss[2] == 'A') && (ss[3] == 'n' || ss[3] == 'N'))
+    {
+        if (success) *success = OFTrue;
+        return OFnumeric_limits<double>::quiet_NaN();
+    }
+
     // handle positive infinity as a special case, since iostream does not
     if ((ss.length() >= 3) && (ss[0] == 'i' || ss[0] == 'I') && (ss[1] == 'n' || ss[1] == 'N') && (ss[2] == 'f' || ss[2] == 'F'))
     {
@@ -2017,6 +1953,9 @@ double OFStandard::atof(const char *s, OFBool *success)
 
 #else /* ENABLE_IOSTREAM_BASED_ATOF_IMPLEMENTATION */
 
+// This is the implementation in use when ENABLE_CSTDIO_BASED_ATOF_IMPLEMENTATION
+// is defined.
+
 #ifdef _WIN32
 
     // Windows has a sscanf version where we can explicitly pass a locale
@@ -2435,6 +2374,9 @@ static void ftoa_convert(
 
 #else /* ENABLE_IOSTREAM_BASED_FTOA_IMPLEMENTATION */
 
+// This is the implementation in use when ENABLE_CSTDIO_BASED_FTOA_IMPLEMENTATION
+// is defined.
+
 static void ftoa_convert(
   char *dst,
   size_t siz,
@@ -2527,7 +2469,7 @@ void OFStandard::ftoa(
     if (!success || d != val)
     {
       // really need precision 17 (DBL_DECIMAL_DIG)
-      ftoa_convert(dst, siz, val, flags, width, prec);
+      ftoa_convert(dst, siz, val, flags, width, 17);
     }
   }
   else
@@ -3073,10 +3015,8 @@ long OFStandard::getProcessID()
 {
 #ifdef _WIN32
   return _getpid();
-#elif defined(HAVE_GETPID)
-  return getpid();
 #else
-  return 0; // Workaround for MAC
+  return getpid();
 #endif
 }
 
index c1df7068e3aad8c0a7727a1320b766afc08da595..f1685de8c606cadb7bcac9e2400ea8deba0a5afa 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2024, OFFIS e.V.
+ *  Copyright (C) 2024-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -141,6 +141,11 @@ static OFString getLastErrorString()
   return OFString();
 }
 
+#elif defined(__APPLE__)
+
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+
 #else /* _WIN32 */
 
 extern char** environ; // required to exist by the Single Unix Specification
@@ -156,16 +161,42 @@ int OFstub_main(int argc, char** argv, const char *stubName, const char *appName
       return EXITCODE_ILLEGAL_PARAMS;
     }
 
+    long len = 43 - OFstatic_cast(long, strlen(stubName)) - OFstatic_cast(long, strlen(appName));
+    if (len < 0) len = 0;
+
 #ifdef DCMTK_USE_OFLOG_LOGGER_IN_STUB
     OFString logger_name = "dcmtk.apps.";
     logger_name += stubName;
     OFLogger logger = OFLog::getLogger(logger_name.c_str());
-#endif
 
-#ifdef DCMTK_USE_OFLOG_LOGGER_IN_STUB
-      OFLOG_WARN(logger, stubName << " is deprecated, use " << appName << " instead");
+    OFString output =
+        "##########################################################################\n"
+        "#                                                                        #\n#";
+    output.append(len/2, ' ');
+    output.append(stubName);
+    output.append(" is deprecated, use ");
+    output.append(appName);
+    output.append(" instead!");
+    output.append(len - (len/2), ' ');
+    output.append("#\n"
+        "#                                                                        #\n"
+        "##########################################################################\n");
+      OFLOG_WARN(logger, output);
 #else
-      fprintf(stderr, "W: %s is deprecated, use %s instead\n", stubName, appName);
+    OFString output =
+        "W: ##########################################################################\n"
+        "W: #                                                                        #\nW: #";
+    output.append(len/2, ' ');
+    output.append(stubName);
+    output.append(" is deprecated, use ");
+    output.append(appName);
+    output.append(" instead!");
+    output.append(len - (len/2), ' ');
+    output.append("#\n"
+        "W: #                                                                        #\n"
+        "W: ##########################################################################\n\n");
+
+    fprintf(stderr, "%s", output.c_str());
 #endif
 
     // get real path in which the stub executable is located
index c3904d29699b8e279e1a922952c47775e8af5ab8..d93b6116287b0f5b500b93aa2c07eaf56f381318 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2023, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were slightly modified by
@@ -328,7 +328,7 @@ char myIsTextWideChar(const void * /*b*/, int /*len*/) { return FALSE; }
         }
         static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) { return fopen(filename,mode); }
         static inline int xstrlen(XMLCSTR c)   { return OFstatic_cast(int, strlen(c)); }
-        #ifdef __BORLANDC__
+        #ifdef HAVE_CLASSIC_BORLAND_COMPILER
             static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return strnicmp(c1,c2,l);}
             static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return stricmp(c1,c2); }
         #else
index 4626df0664c9a4aaf1ecac7beadd06759305f921..061ab129472163130bb9a9ca291ebf7d95b8989a 100644 (file)
@@ -306,13 +306,14 @@ tstring.o: tstring.cc ../../config/include/dcmtk/config/osconfig.h \
  ../include/dcmtk/ofstd/ofstring.h ../include/dcmtk/ofstd/oftypes.h \
  ../include/dcmtk/ofstd/ofdefine.h ../include/dcmtk/ofstd/ofcast.h \
  ../include/dcmtk/ofstd/ofexport.h ../include/dcmtk/ofstd/ofstdinc.h \
- ../include/dcmtk/ofstd/ofstream.h ../include/dcmtk/ofstd/oftest.h \
- ../include/dcmtk/ofstd/ofconapp.h ../include/dcmtk/ofstd/ofcmdln.h \
- ../include/dcmtk/ofstd/ofexbl.h ../include/dcmtk/ofstd/oftraits.h \
- ../include/dcmtk/ofstd/oflist.h ../include/dcmtk/ofstd/ofconsol.h \
- ../include/dcmtk/ofstd/ofthread.h ../include/dcmtk/ofstd/offile.h \
- ../include/dcmtk/ofstd/ofstd.h ../include/dcmtk/ofstd/ofcond.h \
- ../include/dcmtk/ofstd/ofdiag.h ../include/dcmtk/ofstd/diag/push.def \
+ ../include/dcmtk/ofstd/ofstream.h ../include/dcmtk/ofstd/ofstrhlp.h \
+ ../include/dcmtk/ofstd/oftest.h ../include/dcmtk/ofstd/ofconapp.h \
+ ../include/dcmtk/ofstd/ofcmdln.h ../include/dcmtk/ofstd/ofexbl.h \
+ ../include/dcmtk/ofstd/oftraits.h ../include/dcmtk/ofstd/oflist.h \
+ ../include/dcmtk/ofstd/ofconsol.h ../include/dcmtk/ofstd/ofthread.h \
+ ../include/dcmtk/ofstd/offile.h ../include/dcmtk/ofstd/ofstd.h \
+ ../include/dcmtk/ofstd/ofcond.h ../include/dcmtk/ofstd/ofdiag.h \
+ ../include/dcmtk/ofstd/diag/push.def \
  ../include/dcmtk/ofstd/diag/useafree.def \
  ../include/dcmtk/ofstd/diag/pop.def ../include/dcmtk/ofstd/oflimits.h \
  ../include/dcmtk/ofstd/oferror.h ../include/dcmtk/ofstd/ofexit.h
index b187e277d5abb8b7ac6fcb958ef7c8acfe558216..33398b21a84544d8eddd589b951fc95fcda187a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 2011-2024, OFFIS e.V.
+ *  Copyright (C) 2011-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -52,6 +52,7 @@ OFTEST_REGISTER(ofstd_OFFile);
 OFTEST_REGISTER(ofstd_OFString_compare);
 OFTEST_REGISTER(ofstd_OFString_concatenate);
 OFTEST_REGISTER(ofstd_OFString_constructor);
+OFTEST_REGISTER(ofstd_OFString_conversion);
 OFTEST_REGISTER(ofstd_OFString_copy);
 OFTEST_REGISTER(ofstd_OFString_identity_1);
 OFTEST_REGISTER(ofstd_OFString_identity_2);
index ebed9df8c871d01f77814a2fd89a5b25424ca3a1..f36d921fb743e7d7d474f0705fe6c9ddb057d9c9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1997-2019, OFFIS e.V.
+ *  Copyright (C) 1997-2025, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -37,6 +37,7 @@
 #include "dcmtk/config/osconfig.h"     /* include OS specific configuration first */
 
 #include "dcmtk/ofstd/ofstring.h"
+#include "dcmtk/ofstd/ofstrhlp.h"
 #define OFTEST_OFSTD_ONLY
 #include "dcmtk/ofstd/oftest.h"
 
@@ -295,3 +296,36 @@ OFTEST(ofstd_OFString_identity_3)
 {
   identitytest(X+Y+N+X+Y+N, "A string that will be used in identitytest but is otherwise just another useless string.");
 }
+
+OFTEST(ofstd_OFString_conversion)
+{
+  // convert an OFString to std::string
+  OFString a("ABC");
+  STD_NAMESPACE string b = OFString_to_std_string(a);
+  OFCHECK_EQUAL(b.length(), 3);
+  OFCHECK_EQUAL(b.at(0), 'A');
+  OFCHECK_EQUAL(b.at(1), 'B');
+  OFCHECK_EQUAL(b.at(2), 'C');
+
+  // convert an OFString containing a null byte to std::string
+  a.at(1)= '\0';
+  STD_NAMESPACE string cc = OFString_to_std_string(a);
+  OFCHECK_EQUAL(cc.length(), 3);
+  OFCHECK_EQUAL(cc.at(0), 'A');
+  OFCHECK_EQUAL(cc.at(1), '\0');
+  OFCHECK_EQUAL(cc.at(2), 'C');
+
+  // convert a std::string to OFString
+  OFString d = std_string_to_OFString(b);
+  OFCHECK_EQUAL(d.length(), 3);
+  OFCHECK_EQUAL(d.at(0), 'A');
+  OFCHECK_EQUAL(d.at(1), 'B');
+  OFCHECK_EQUAL(d.at(2), 'C');
+
+  // convert a std::string containing a null byte to OFString
+  OFString e = std_string_to_OFString(cc);
+  OFCHECK_EQUAL(e.length(), 3);
+  OFCHECK_EQUAL(e.at(0), 'A');
+  OFCHECK_EQUAL(e.at(1), '\0');
+  OFCHECK_EQUAL(e.at(2), 'C');
+}